2012-12-13 94 views
1

使用EF DbContext。我的實體對象有rowversion列(SQL Compact版本第4版),它用於併發檢查(ConcurrencyMode = Fixed,StoreGeneratedPattern = Computed)。DbContext,處理併發異常

要強制實現併發異常,從UI讀取2種不同形式的相同表記錄,編輯它們中的每一個,然後一個接一個地保存。以下代碼執行實際的保存操作。

當點擊第二個窗體上的保存按鈕時,按預期發生併發錯誤。但是, 在從數據庫中複製原始值之後,第二次嘗試時異常仍然存在。只有第三次嘗試成功沒有任何錯誤。有人能解釋我可能會導致這個問題嗎?

try 
{ 
    _ctx.SaveChanges(); //first attempt 
} 
catch (Exception ex) 
{ 
    if (ex is DbUpdateConcurrencyException) 
    { 
    var exc = ex as DbUpdateConcurrencyException; 
    foreach (var entry in exc.Entries) 
     entry.OriginalValues.SetValues(entry.GetDatabaseValues()); 
    try 
    { 
     _ctx.SaveChanges(); //second attempt 
    } 
    catch (Exception ex2) 
    { 
     if (ex2 is DbUpdateConcurrencyException) 
     { 
     var exc2 = ex2 as DbUpdateConcurrencyException; 
     foreach (var entry in exc2.Entries) 
      entry.OriginalValues.SetValues(entry.GetDatabaseValues()); 
     try 
     { 
      _ctx.SaveChanges(); //third attempt 
     } 
     catch (Exception ex3) 
     { 
      System.Windows.MessageBox.Show(ex3.Message); 
     } 
     } 
    } 
    } 
} 

編輯:我發現它發生在我通過UI進行更新時。如果在上面的代碼,第一次嘗試之前,我做了什麼如下:

var _ctx2 = new MyDbContext(); 
var myEntity = _ctx2.MyEntities.Where(ent => ent.Id == 2).Single(); 
myEntity.Name = "My new name"; 
_ctx2.SaveChanges(); 
_ctx2.Dispose(); 

然後代碼工作正常,因爲myEntity所的另一個實例是通過UI更新;即第二次嘗試將拯救我的實體。 而且,問題出在下面一行:

foreach (var entry in exc.Entries) 
    entry.OriginalValues.SetValues(entry.GetDatabaseValues()); 

因爲,當通過UI更新,exc.Entries返回沒有哪個併發錯誤發生的實體,但它的導航屬性的實體。

在這種情況下,MyEntity是一個樹狀自引用實體,它具有兩個導航屬性:ParentEntity和Children。

因此,在第一次保存嘗試後,我在exc.Entries中的內容是ParentEntity(處於未更改狀態),並且只有在第二次保存嘗試後,exc.Entries纔會返回引發併發錯誤的實際實體。

+0

'注意:'您可以使用'catch(DbUpdateConcurrencyException ex)'而不是使用if檢查異常類型。 – NaveenBhat

回答

1

好吧,它似乎是一個EF錯誤。參見以下:

http://support.microsoft.com/kb/2390624#appliesto 
http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/ce60bf40-cd05-42f6-ab8f-26b048ec83d7