【问题标题】:Entity Framework 5 using Db Transactions "connection is already part of a local or distributed transaction"使用 Db 事务的实体框架 5“连接已经是本地或分布式事务的一部分”
【发布时间】:2015-02-10 13:41:31
【问题描述】:

我对事务和实体框架 5 没有任何运气。我有以下代码:

 context.Database.Connection.Open();
 transaction = context.Database.Connection.BeginTransaction(IsolationLevel.Serializable);
//some work happens
context.SaveChanges();
//some additional work
context.SaveChanges();
transaction.Commit();

在第一个 context.SaveChanges 调用中,我得到一个异常:“连接已经是本地或分布式事务的一部分”

现在我实际上只是在做一个简单的概念证明,我所做的只是附加一个实体,将其标记为已修改,然后调用保存更改。

作为故障排除处理,我放置了一个事件处理程序,用于处理连接状态何时发生变化并在其中设置断点。这样做,我验证了在我开始事务和调用保存更改之间的连接没有关闭。

任何帮助弄清楚它为什么给我这个例外将不胜感激。

【问题讨论】:

  • 我还没有找到任何关于事务如何与 EF 5 一起工作的信息。我找到了一篇关于 EF 6 和更新版本的事务的文章,但我们没有使用 EF 6,因为 oracle 数据访问 dll 不是t 生产就绪。我最初的概念证明似乎表现得像 EF 不希望在事务期间对 context.SaveChanges 进行任何调用。如果我取出中间保存更改并在提交后仅保存更改,它在我的琐碎 POC 中表现正确。
  • 什么是堆栈跟踪?
  • 堆栈跟踪深入到 oracle 数据访问 dll 并出现错误。从逻辑上讲,我看到任何 context.savechanges 是一个事务,所以看来 EF 在幕后做了一个事务。因此,在这方面,自己开始交易的概念在实体框架中显得毫无意义。

标签: entity-framework transactions entity-framework-5


【解决方案1】:

如果由于某种原因您必须在一个事务中进行多次SaveChanges 调用,推荐的方法是将它们包装在TransactionScope 中:

using(var tran = new TransactionScope())
{
    using(var context = new MyContext())
    {
        //some work happens
        context.SaveChanges();
        //some additional work
        context.SaveChanges();
    }

    tran.Complete(); // without this call the transaction is rolled back.
}

default isolation level is serializable。在事务中打开的每个连接都在此事务中登记。默认情况下,EF 在执行查询时总是打开和关闭连接。

我猜你得到这个异常的原因是 EF 在执行SaveChanges 时自己创建了一个事务对象。它试图使用它的连接来启动这个事务,但是这个连接已经是你创建的事务的一部分。通过使用 TransactionScope,EF 事务只是在环境事务中登记。

【讨论】:

    【解决方案2】:

    这是我们之前使用事务的方式。它对我们有用:

    public void DoSomething()
    {
       using (var db = GetContext())
       {
            using (var ts = GetTransactionScope())
            {
                //do stuff
                db.SaveChanges();
                ts.Complete();
            }
       }
    }
    
    public TransactionScope GetTransactionScope()
    {
        var tso = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
        return new TransactionScope(TransactionScopeOption.Required, tso);
    }
    

    【讨论】:

    • 所以我看到很多这样的例子,但是当我们似乎通过 context.Database.Connection 获得了特定的 DbTransaction 方法时,我的下意识反应是回避这种情况。在我看来,我们在 EF5 中获得了这一点真的很奇怪,但根本没有人使用它。想法?
    • 正如我所看到的,您在给定数据库上下文中获得的行为本质上是事务性的。因此 context.SaveChanges() 与事务一起使用是有道理的。从某种意义上说,如果您要使用实体框架,那么开始您自己的事务似乎并没有真正的内在价值,因为根据定义,上下文中的所有工作本身就是一个事务。我想它仍然是必要的,因为在数据库级别,如果你足够疯狂想要这样做,你可以运行自己的 sql 命令。
    猜你喜欢
    • 1970-01-01
    • 2014-12-28
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 1970-01-01
    相关资源
    最近更新 更多