[英]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.