【发布时间】:2019-10-03 11:23:04
【问题描述】:
我有一点竞争条件,DB 中的一行可能由两个线程同时创建。为了解决这个问题,我实现了重试,如下所示:
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:无法在其中插入重复的键行 具有唯一索引“IX_Table_field1_field2”的对象“dbo.Table”。这 重复键值为 (val1, val2)。
为什么 FirstOrDefault 会返回 null,即使该行明确存在于数据库中? 我正在使用 Microsoft.AspNetCore.All v.2.1.4
编辑:澄清。上下文未在线程之间共享。当多个 HTTP 请求同时到达时,就会发生争用。上下文被注入控制器(此代码所在的位置)。它使用默认设置注册了 AddDbContext 调用,使其 ServiceLifetime 作用域。
解决方案:Fenixil 的评论给了我必要的提示。添加但未保存的行仍保留在上下文中并不断尝试插入。我保留了对新行的引用并将其添加到 catch 块中:
context.Entry(NewRow).State = EntityState.Detached;
【问题讨论】:
-
请投票给对你有用的答案。
标签: c# .net-core entity-framework-core