У меня происходит некоторое состояние гонки, когда строка в БД может быть создана двумя потоками одновременно.Чтобы обойти это, я реализовал повторные попытки, например, так:
int retries = 0;
while (true)
{
try
{
var saved = context.Table.FirstOrDefault(x => x.field1 == val1 && x.field2 == val2);
if (saved != null)
{
//edits saved
}
else
{
context.Table.Add(new Table
{
field1 = val1,
field2 = val2
});
}
await context.SaveChangesAsync();
return Json(true);
}
catch (Exception e)
{
if (retries >= 5)
throw (e);
retries++;
}
}
Почему-то 5 раз подряд происходит сбой с такой же ошибкой:
Microsoft.EntityFrameworkCore.DbUpdateException: Произошла ошибка при обновлении записей.Смотрите внутреннее исключение для деталей.---> System.Data.SqlClient.SqlException: Невозможно вставить повторяющуюся строку ключа в объект 'dbo.Table' с уникальным индексом 'IX_Table_field1_field2'.Значение ключа-дубликата: (val1, val2).
Почему FirstOrDefault возвращает ноль, даже если строка явно существует в базе данных?Я использую Microsoft.AspNetCore.All v.2.1.4
EDIT: для пояснения.Контекст не передается между потоками.Гонка происходит, когда несколько HTTP-запросов поступают одновременно.Контекст вводится в контроллер (где находится этот код).Он был зарегистрирован с помощью вызова AddDbContext с настройками по умолчанию, что делает его ServiceLifetime ограниченным.
РЕШЕНИЕ: комментарий Фениксила дал мне необходимую подсказку.Добавленная, но несохраненная строка остается в контексте и пытается вставить ее.Я сохранил ссылку на новую строку и добавил ее в блок catch:
context.Entry(NewRow).State = EntityState.Detached;