簡體   English   中英

具有多個線程的實體框架事務

[英]Entity Framework Transaction With Multiple Threads

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

但是,線程都在共享事務下運行。 原始線程創建一個TransactionScope,它生成的每個線程使用主線程上的Transaction中的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添加到我的連接字符串中,這沒有任何區別。

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

問題在這里描述:

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

鎖定SaveChanges和Refresh調用很容易,但是為了確保在查詢執行期間發生鎖定,我必須創建一個在執行查詢時鎖定的虛擬查詢提供程序。 我真的不應該這樣做。 實體框架應該足夠強大,可以開箱即用......特別是考慮到你並不打算處理你自己的連接創建。

這是查詢提供程序包裝器的代碼。 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);
            }
        }
    }

如果要將依賴克隆的相同實例傳遞給多個線程,然后在每個線程上處理它們,那么可能會導致這樣的行為(例如,提交已完成的事務等)。 AFAIK,每個線程需要一個單獨的依賴克隆。

另一種可能性是,在線程完成交易之前,“父”交易正在完成或處置。 離開主TranscationScope之前,請確保您的異步工作已完成(盡管可以將此設置為在未完成的子事務上阻止)。

對不起,沒有超過您所描述的內容。

祝你好運,邁克爾

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM