Jef*_*eff 7 c# multithreading entity-framework transactions transactionscope
我有一个运行多个线程的应用程序.线程不共享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:
Run Code Online (Sandbox Code Playgroud)
我只知道它们同时运行,因为当我在调试模式下运行单元测试并弹出此异常时,如果我查看正在运行的不同线程,我总是看到在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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4428 次 |
| 最近记录: |