7

我有一個應用程序運行多個線程。線程不共享ObjectContext(每個線程都有自己的 - 我知道它們不是線程安全的)。實體框架事務與多個線程

然而,線程都共享事務下操作。原始線程創建一個TransactionScope並且它產生的每個線程使用主線程上的事務處理中的DependentTransaction創建一個TransactionScope。

當多個ObjectContext的請求在同一時間運行,我有時(不一致)出現錯誤:

System.Data.EntityException occurred 
    Message=An error occurred while closing the provider connection. See the inner exception for details. 

    InnerException: System.Transactions.TransactionException 
     Message=The operation is not valid for the state of the transaction. 
     Source=System.Transactions 
     StackTrace: 
      at System.Transactions.TransactionStatePSPEOperation.get_Status(InternalTransaction tx) 
      at System.Transactions.TransactionInformation.get_Status() 
      at System.Data.ProviderBase.DbConnectionInternal.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) 
      at System.Data.SqlClient.SqlInternalConnection.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) 
      at System.Data.SqlClient.SqlConnection.Close() 
      at System.Data.EntityClient.EntityConnection.StoreCloseHelper() 
     InnerException: 

我只知道他們是在同一時間運行,因爲當我在調試運行我的單元測試模式,並且這個異常會彈出,如果我查看正在運行的不同線程,我總會看到至少有一個其他線程在ObjectContext操作中停止。

而且,做一些閱讀後,我嘗試添加multipleactiveresultsets=False我的連接字符串並沒有什麼區別。

這是實體框架中的錯誤嗎?

回答

1

的問題說明如下:

http://www.b10g.dk/2007/09/07/dependenttransaction-and-multithreading/

這是很容易鎖定的SaveChanges和刷新電話,但爲了確保鎖查詢執行過程中發生在執行查詢時,我必須製作一個虛擬查詢提供程序來鎖定它。我真的不應該這樣做。實體框架應該已經足夠健壯以處理這種開箱即用的問題......特別是考慮到您不打算處理自己的連接創建。

下面是查詢提供包裝的代碼。該IQueryables自己和基QueryProvider類都基於簡單的可重用實現這裏 http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx

/// <summary> 
    /// A wrapper for queries executed by EF. 
    /// </summary> 
    internal class EntityFrameworkQueryProvider : QueryProvider 
    {  
     protected override object Execute(Expression expression) 
     { 
      try 
      { 
       // this is required due to a bug in how EF multi-threads when Transactions are used. 
       if (Transaction.Current != null) Monitor.Enter(EntityFrameworkExtensions.SyncRoot); 

       // enumerate is a simple extension method that forces enumeration of the IQueryable, thus making it actually get executed during the lock 
       return Expression.Lambda(expression).Compile().DynamicInvoke().Enumerate(); 
      } 
      finally 
      { 
       if (Transaction.Current != null) Monitor.Exit(EntityFrameworkRepositoryProvider.SyncRoot); 
      } 
     } 
    } 
+0

您的答案基於您的鏈接不再工作。你能否提供更多關於根本原因的信息? – 2016-07-19 10:44:23

+1

用於輸入鎖定的SyncRoot與離開時使用的SyncRoot不同。 – 2016-07-19 10:47:06

0

如果您傳遞相關克隆的同一個實例,以多個線程,然後在每個線程上處置他們,這可能導致這樣的行爲(如提交完成的交易,這樣的)。 AFAIK,你需要一個單獨的從屬克隆每個線程。

另一種可能性是「父」的事務是越來越完結或之前的螺紋與他們的交易完成。確保在離開主TranscationScope之前完成異步工作(儘管可以設置爲阻止未完成的子事務)。

對不起,沒有比這更與你所描述的東西。

祝你好運, 邁克爾

+0

我所有的新主題交易的依賴克隆和之前的任何子線程的父線程沒有完成交易。任何其他想法?謝謝。 – Jeff 2011-05-26 21:49:51