如果 EF 上下文是从 SqlConnection 创建的,则出现 EntityCommandExecutionException

EntityCommandExecutionException if EF context is created from SqlConnection

在长时间的 运行ning 批处理事务中 运行ning 主要使用直接 SQL 语句,我想使用一个 EF 语句,它应该 运行 作为当前交易。

我查看了 DbContext 的构造函数并提出了以下方法:

using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ResPlannerContext"].ConnectionString))
{
    connection.Open();
    SqlTransaction trans = connection.BeginTransaction();
    using (ResPlannerContext context = new ResPlannerContext(trans.Connection, false))
    {
        var data = context.Activities.Where(x => x.StartDate < DateTime.Today);
        Console.WriteLine("Count: " + data.Count());
    }
}

好消息:编译成功。坏的:弹出以下异常:

Message=An error occurred while executing the command definition. See the inner exception for details.
Source=EntityFramework
StackTrace:
   bei System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
   bei System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
   bei System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
   bei System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   bei System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
   bei System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   bei System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   bei System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
   bei System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   bei System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
   bei System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3[TResult](IEnumerable`1 sequence)
   bei System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   bei System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
   bei System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
   bei System.Linq.Queryable.Count[TSource](IQueryable`1 source)
   bei ConsoleApplication3.Program.Main(String[] args) in c:\Users\sreindl\Documents\Visual Studio 2013\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs:Zeile 26.
   bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   bei System.Threading.ThreadHelper.ThreadStart()
InnerException: System.InvalidOperationException
   _HResult=-2146233079
   _message=ExecuteReader erfordert, dass der Befehl über eine Transaktion verfügt, wenn die dem Befehl zugewiesene Verbindung eine ausstehende lokale Verbindung ist. Die Transaction-Eigenschaft des Befehls wurde nicht initialisiert.
   HResult=-2146233079
   IsTransient=false
   Message=ExecuteReader erfordert, dass der Befehl über eine Transaktion verfügt, wenn die dem Befehl zugewiesene Verbindung eine ausstehende lokale Verbindung ist. Die Transaction-Eigenschaft des Befehls wurde nicht initialisiert.
   Source=System.Data
   StackTrace:
        bei System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
        bei System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
        bei System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
        bei System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
        bei System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
        bei System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
        bei System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext`1 c)
        bei System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
        bei System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
        bei System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
        bei System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
        bei System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
   InnerException: 

里面的德语异常(抱歉使用德语 SQL 服务器 :-) 意味着:ExecuteReader 要求命令在分配给命令的连接处于挂起的本地传输时具有事务。

实际上没有设置内部 SqlCommand 的 Transaction 属性。

你知道如何处理这种情况吗?

是否有以下可能:

using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ResPlannerContext"].ConnectionString))
{
    connection.Open();
    using (ResPlannerContext context = new ResPlannerContext(connection, false))
    {
        using (var tran = context.Database.BebinTransaction() ) {
            var data = context.Activities.Where(x => x.StartDate < DateTime.Today);
            Console.WriteLine("Count: " + data.Count());

            tran.Commit();
        }
    }
}

否则,如所述here

using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ResPlannerContext"].ConnectionString))
{
    connection.Open();
    SqlTransaction trans = connection.BeginTransaction();
    using (ResPlannerContext context = new ResPlannerContext(trans.Connection, false))
    {
        context.Database.UseTransaction(trans);

        var data = context.Activities.Where(x => x.StartDate < DateTime.Today);
        Console.WriteLine("Count: " + data.Count());
    }
}

我认为您应该为此编写两个单独的事务。一个应该是连接事务,另一个是 SQLTransaction:

string connString = ConfigurationManager.ConnectionStrings["db"].ConnectionString;
using (var conn = new SqlConnection(connString))
{
    conn.Open();
    using (IDbTransaction tran = conn.BeginTransaction())
    {
        try
        {
            // transactional code...
            using (SqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = "INSERT INTO Data(Code) VALUES('A-100');";
                cmd.Transaction = tran as SqlTransaction;
                cmd.ExecuteNonQuery();
            }
            tran.Commit();
        }
        catch(Exception ex)
        {
            tran.Rollback();
            throw;
        }
    }
}

检查下面 link 中的 post 由 S.M.Ahasan Habib 解释了上面的代码: http://www.codeproject.com/Articles/690136/All-About-TransactionScope