【问题标题】:Entity Framework Optimistic Concurrency Exception Handling实体框架乐观并发异常处理
【发布时间】:2015-06-27 14:21:07
【问题描述】:

我正在尝试解决 EF 6 上的乐观并发控制问题。我目前想要捕获 DBUpdateConcurrencyException,然后刷新实体。但是我目前收到此异常:

System.InvalidOperationException: 中索引 0 处的元素 要刷新的对象集合具有 null EntityKey 属性值 或未附加到此 ObjectStateManager。

这里是显示目的的代码的简化版本:

using (var dbContextTransaction = dbContext.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
    try
    {
        dbContext.Commit();
    }
    catch(DbUpdateConcurrencyException ex)
    {
        ((IObjectContextAdapter)KnowledgebaseContext).ObjectContext.Refresh(RefreshMode.StoreWins, en);
        dbContextTransaction.Rollback();
    }
}

我在 Google 或 SO 上找不到太多关于此异常的信息。任何帮助将不胜感激。

【问题讨论】:

  • 您从调试中收集的数据在哪里?模型看起来如何?它是如何映射的?它的关键属性的价值是多少?对象是否附着?
  • 如果您尝试向数据库中添加某些内容,则需要在尝试刷新集合之前将其删除。现在,我认为,当您尝试刷新集合时,集合中有一个实体尚未保存在数据库中,也未附加到状态管理器
  • @SaagarEliasJacky 实际上很有帮助。您是否知道我可以使用的资源或文章对此进行进一步解释?
  • “来自两个单独连接的同一实体”可能会导致问题,因为它没有附加在正确的上下文中,是的。虽然如果你说键值为null,那异常有什么不清楚的地方?

标签: c# entity-framework


【解决方案1】:

通过查看thisthis,我已经能够解决这个问题。关于此功能的文档相当稀缺。

所以这是场景(我们假设已经有一个 TimeStamp 列,其值会随着每次数据库更新而更新):

UserA 读取 Entity1 并开始进行更改。当 UserA 进行更改时,userB 读取 Entity1,对其进行更改并将其保存到数据库中。现在 UserA 想要保存她的更改,但现在根据定义,她读取的确切实体不再存在。原因是该实体的存在也取决于 TimeStamp 列,它不再是相同的旧值。因此,当我尝试刷新 UserA 知道存在的 Entity1 时,我遇到了一个异常,我也无法Refresh

现在我们将看看现有更新实体的并发问题的两种可能解决方案:

  • Ignore UserA's Changes(store wins):这基本上意味着将Refresh 来自数据库的实体。为此,应使用现在驻留在数据库中的新字段覆盖 UserA 上下文中 Entity1 的 TimeStamp 字段,然后尝试从服务器刷新信息。这样,可以在 Entity1 中定位、检索和填充正确的实体,覆盖本地更改。看看here 的其他方法。
  • 覆盖数据库上的更改(客户端获胜):在这里,我们将覆盖 TimeStamp 字段,然后再次尝试更新。通过这样做,EF 将不再将更新检测为冲突,并且服务器上的数据将被覆盖。前面提到的链接也包含此案例的示例。

我不确定为什么在使用 Refresh 方法时会出现异常。我改用SetValuesGetDatabaseValues 等,我的问题就解决了。

【讨论】:

    猜你喜欢
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    相关资源
    最近更新 更多