2017-06-17 48 views
3

我在帶有Web客戶端的Web API服務器上使用EF 6.x(代碼優先),我需要實現併發處理。問題是我甚至無法讓EF生成異常。EF不會拋出DbUpdateConcurrencyException,儘管發生衝突更新

我發現的大多數例子似乎都沒有使用「分離的實體」,DTO被髮送到Web客戶端進行更新,然後在稍後保存回服務器(這是我的場景) 。

比方說,我有一個公司的記錄:

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

    [Timestamp] 
    public byte[] RowVersion { get; set; } 
} 

1)用戶A拉起公司Id = 0,RowVersion是0x0000000000002B0A

2)我跑UPDATE Company SET CompanyName = 'Acme Changed, Inc.' WHERE CompanyId = 0來模擬另一個用戶的改變。 RowVersion更改爲0x0000000000002B0B

3)用戶A將公司名稱更改爲「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). 
    } 
} 

相反併發異常的,它只是保存記錄和更新RowVersion到0x0000000000002B0C 。

我錯過了什麼?

我需要一種方法來檢測更改,刪除等,以防止保存髒數據。我想我可以推出自己的檢查,但實際的對象與許多嵌套的子對象(一個或多個級別)複雜。

關於這個最佳做法的任何指針也將不勝感激...

+0

您描述的問題沒有併發問題。您正在從數據庫獲取最新版本的數據並對其進行更新並保存。爲什麼EF會遇到問題。如果正在更新的行已被刪除或被其他查詢鎖定,或者兩個進程試圖同時更改同一行,則這些coluld會出現問題。但大部分時間,EF和SQL Server都盡力處理它。 –

+1

@ChetanRanpariya我的想法是,EF會檢測到我試圖保存的記錄的RowVersion與DB中的記錄不匹配,從而知道該記錄很髒。如果不是這種情況,在這種情況下處理上述併發問題的正確/最佳做法是什麼? – Lars335

+0

在您的示例中,您不保存之前檢索的行。您正在檢索並保存最新版本的行。我不確定你在這裏有什麼打算。您是在解決真正的應用程序問題還是隻是開始瞭解EF?這裏的用例究竟是什麼?如果實體被其他進程修改,您是否希望EF引發異常?你可以查看https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework -in-an-asp-net-mvc-application –

回答

3

我得到了這個工作。在我的問題的第5步,我改變了這一行:

dbCompany.RowVersion = updatedCompany.RowVersion; 

要這樣:

Context.Entry(dbCompany).OriginalValues["RowVersion"] = updatedCompany.RowVersion; 

現在EF試圖挽救髒數據時拋出一個DbUpdateConcurrencyException!

+0

太棒了。我看到的大多數教程都使用TryUpdateModel,我拒絕在我的MVC應用程序中使用它。這爲我做了詭計。 – William