具有多线程的实体框架事务
我有一个运行多个线程的应用程序。线程不共享 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
添加到我的连接字符串中,但这没有什么区别。
这是实体框架中的错误吗?
I have an application running multiple threads. The threads do NOT share an ObjectContext (each thread has its own - I know they are not thread safe).
However, the threads are all operating under a shared Transaction. The original thread creates a TransactionScope and each thread it spawns creates a TransactionScope using a DependentTransaction from the Transaction on the main thread.
When multiple ObjectContext requests run at the same time, I sometimes (not consistently) get the error:
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:
I only know they are running at the same time because when I run my unit tests in debug mode and this exception pops up, if I look at the different threads that are running, I always see at least one other thread halted at an ObjectContext operation.
Also, after doing some reading, I tried adding multipleactiveresultsets=False
to my connection string and that made no difference.
Is this a bug in Entity Framework?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
该问题如下所述:
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
The problem is described here:
http://www.b10g.dk/2007/09/07/dependenttransaction-and-multithreading/
It's easy enough to lock the SaveChanges and Refresh calls, but in order to make sure locks occur during query execution I had to make a dummy query provider that locks when executing queries. I really shouldn't have had to do this. Entity Framework should have been robust enough to handle this out of the box...especially considering you're not meant to handle your own connection creation.
Here is the code for the query provider wrapper. The IQueryables themselves and the base QueryProvider class are simple reusable implementations based off here
http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx
如果您将依赖克隆的相同实例传递给多个线程,然后在每个线程上处理它们,则可能会导致类似这样的行为(例如提交已完成的事务等)。 AFAIK,每个线程都需要一个单独的依赖克隆。
另一种可能性是“父”事务在线程完成其事务之前完成或处置。确保在离开主 TranscationScope 之前完成异步工作(尽管可以将其设置为阻止未完成的子事务)。
抱歉,您所描述的内容仅此而已。
祝你好运,
迈克尔
If you are passing the same instance of the dependent clone to multiple threads, and then disposing of them on each thread, that could lead to behavior like this (e.g. committing a finished transaction and such). AFAIK, you need a separate dependent clone per thread.
Another possibility is the "parent" transaction is getting completed or disposed before the threads finish with their transaction. Make sure your async work is done before you leave the main TranscationScope (although this can be set to block on unfinished child transactions).
Sorry, don't have more than that with what you've described.
Good luck,
Michael