具有多线程的实体框架事务 [英] Entity Framework Transaction With Multiple Threads

查看:85
本文介绍了具有多线程的实体框架事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个运行多个线程的应用程序.线程不共享ObjectContext(每个线程都有其自己的-我知道它们不是线程安全的).

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).

但是,所有线程都在共享事务下运行.原始线程创建一个TransactionScope,它产生的每个线程都使用主线程上的Transaction中的DependentTransaction创建一个TransactionScope.

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.

当多个ObjectContext请求同时运行时,有时(不一致)出现错误:

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: 

我只知道它们在同一时间运行,因为当我在调试模式下运行单元测试时,此异常弹出,如果我查看正在运行的不同线程,我总是会看到至少有一个其他线程停止在一个ObjectContext操作.

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.

此外,在阅读后,我尝试将multipleactiveresultsets=False添加到我的连接字符串中,但这没有任何区别.

Also, after doing some reading, I tried adding multipleactiveresultsets=False to my connection string and that made no difference.

这是Entity Framework中的错误吗?

Is this a bug in Entity Framework?

推荐答案

问题在这里描述:

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

锁定SaveChanges和Refresh调用很容易,但是为了确保在查询执行期间发生锁定,我不得不创建一个虚拟查询提供程序,该提供程序在执行查询时会锁定.我真的不应该这样做.实体框架应该足够健壮,可以立即使用它...尤其是考虑到您无意处理自己的连接创建.

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.

这是查询提供程序包装程序的代码. IQueryables本身和基础QueryProvider类都是基于此处的简单可重用实现. http ://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx

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

    /// <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);
            }
        }
    }

这篇关于具有多线程的实体框架事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆