2011-10-19 68 views
0

我有一個商業案例,其中,對於給定源表中的每個記錄,需要對不同表中的多個更改進行處理,並且每個這些sourceTable記錄需要單獨處理。TPL與實體框架更新

所以我有以下pseodocode:

MyEntityFrameworkContext ctx; 
foreach (sourceRecord sr in ctx.sourceTable) 
{ 
    try 
    { 
     using (MyEntityFrameworkContext tctx = new MyEntityFramworkContext) 
     { 
      string result1 = MakeUpdatesToSomeOtherTable1(tctx); 
      sr.Result1 = result1; 
      string result2 = MakeUpdatesToSomeOtherTable2(tctx); 
      sr.Result2 = result2; 
      // will be more tables here. 
      using (TransactionScope ts = new TransactionScope) 
      { 
       tctx.SaveChanges; // to save changes made to OtherTable1 and OtherTable2 
       tctx.ExecuteStoreCommand("SQL that makes a few other changes related to sourceRecord to tables that are NOT in the EF context"); 
       ts.Complete(); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
    sr.ExceptionResult = ex.Message(); 
    } 
}); 
ctx.SaveChanges(); // to save all changes made to sourceTable. 

的原因循環中的TCTX和TransactionScope的是,我需要更改到OtherTables1 & 2被保存在一個事務與調用每個正在處理的sourceRecord的tctx.ExecuteStoreCommand()。

另請注意,我需要將寫入到SourceTable的結果保存爲獨立於對TransactionScope中更新的表所做的更改。因此,我不能在同一個TransactionScope中包含sourceTable的更新,因爲如果該txn回退,我將不會記錄該異常。這樣,在整個過程結束時,我可以看到哪些sourceRecords失敗以及哪些成功。

上面的僞代碼完美地工作。

但是,我想利用這裏的並行性,並將foreach轉換爲Parallel.ForEach()。但後來我遇到了非常意外的錯誤(如調用ts.Complete()後的TransactionAbortedException,調用ctx.SaveChanges()時的NullReferenceException或設置sourceRecord的Result屬性之一時,有時會得到InvalidOperationException:EntityMemberChanged或EntityComplexMemberChanged被調用首先在具有相同屬性名稱的相同更改跟蹤器上調用EntityMemberChanging或EntityComplexMemberChanging)。

因此,我認爲並行,雖然完美的QUERIES,不適合EntityFramwork中的數據更新?我錯過了什麼,或者不瞭解並行性?我不明白爲什麼我的上述方法轉換爲使用並行性時會中斷。任何意見,將不勝感激。

回答

1

EF對象上下文不是線程安全的,所以當多個線程在相同的上下文中嗡嗡作響時,發生災難性錯誤的可能性很大。

看起來您至少有一個foreach循環之外的並且在線程之間共享的上下文對象。

根據你的描述,我猜想來自多個線程的sourceRecord實體的更新屬性正在破壞上下文中的某些內部狀態 - 可能是它維護的用於更改跟蹤的數據集合。

+0

我基本上通過創建一個WCF服務來解決這個問題,並且在try {}塊內調用它,而不是創建一個新的EF上下文根據我的上述代碼。然後,我不得不處理的問題是處理死鎖問題,但通過在服務方法中多次嘗試每次發佈很容易解決這個問題。 –

0

並行性只會給那些CPU綁定的操作帶來好處,在你的情況下,你所做的只是IO操作(數據庫更新等),所以我認爲你不能從中獲得任何好處它並行。但是如果在這個代碼中有CPU綁定的操作,可以使它們在每次更新時都是並行的,但更新將是連續的。

+0

嗯我不同意你的開場白。我理解並行性在任何需要IO的場景(無論是從Web下載,還是通過在EF上下文中調用SaveChanges寫入數據庫)提供特定的好處。我的場景需要對錶更新序列進行多次迭代,每次迭代都與其他迭代隔離。當然這是一個理想的並行性候選人? –

+0

異步編程和並行編程有區別,異步編程對IO有好處。當(在並行代碼中)多個線程將訪問IO資源時,它將包括鎖定,因此你不會得到並行性的好處 – Ankur