尽管更新冲突,但EF不会抛出DbUpdateConcurrencyException

Lar*_*335 8 c# entity-framework asp.net-web-api

我在Web客户端的Web API服务器上使用EF 6.x(代码优先),我需要实现并发处理.问题是我甚至无法获得EF来生成异常.

我发现的大多数示例似乎都没有使用"分离实体",其中DTO被发送到Web客户端,在那里它被更新,然后在以后保存回服务器(这是我的方案).

假设我有公司记录:

public class Company 
{
    int CompanyId { get; set; }
    string CompanyName { get; set; }

    [Timestamp]
    public byte[] RowVersion { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

1)用户A拉出公司Id= 0,RowVersion为0x0000000000002B0A

2)我运行UPDATE Company SET CompanyName = 'Acme Changed, Inc.' WHERE CompanyId = 0模拟另一个用户的更改. RowVersion更改为0x0000000000002B0B

3)用户A将CompanyName更改为"Acme,The Great!" 并单击保存(从浏览器)

4)公司DTO到达Web API服务器CompanyName="Acme,The Great!" 和旧RowVersion= 0x0000000000002B0A

5)我从数据库中检索公司记录,更新并保存:

public void UpdateCompany(Company updatedCompany)
{
    var dbCompany = Context.Companies.SingleOrDefault(r => r.CompanyId == updatedCompany.CompanyId);
    dbCompany.CompanyName = updatedCompany.CompanyName;
    dbCompany.RowVersion = updatedCompany.RowVersion;  // Set RowVersion to the passed in original RowVersion 0x0000000000002B0A

    try
    {
        DbContext.SaveChanges();
    }
    catch (DbUpdateConcurrencyException ex)
    {
        // Expected: exception thrown (but does not happen).
    }
}
Run Code Online (Sandbox Code Playgroud)

它只是将记录和更新保存RowVersion到0x0000000000002B0C ,而不是并发异常.

我错过了什么?

我需要一种方法来检测更改,删除等,以防止保存脏数据.我想我可以滚动自己的检查,但实际的对象很复杂,有很多嵌套的子对象(一个或多个级别).

关于此的最佳实践的任何指针也将受到赞赏......

Lar*_*335 11

我得到了这个工作.在我的问题的第5步中,我改变了这一行:

dbCompany.RowVersion = updatedCompany.RowVersion;  
Run Code Online (Sandbox Code Playgroud)

对此:

Context.Entry(dbCompany).OriginalValues["RowVersion"] = updatedCompany.RowVersion;
Run Code Online (Sandbox Code Playgroud)

现在EF在尝试保存脏数据时抛出DbUpdateConcurrencyException!

  • 所以基本上你的意思是行版本是特殊的并且由 EF 以特殊的方式处理?除非我们更改原始值,否则它完全忽略 RowVersion,原始值是普通 EF 开发人员很少需要研究的低级属性包。您可以看到这非常令人困惑,不是吗?此外,文档还详细介绍了行版本,但只提到修改原始值一次,并将其隐藏在代码示例中。 (2认同)
  • 更优雅一点,因为它不使用字符串作为键(不利于重构等):`Context.Entry(dbCompany).Property(c => c.RowVersion).OriginalValue = UpdatedCompany.RowVersion;` (2认同)