【问题标题】:Single transaction over multiple contexts in Entity Framework 6Entity Framework 6 中多个上下文的单个事务
【发布时间】:2014-08-14 11:59:39
【问题描述】:

我们有一个场景可以在单个事务中保存两个上下文中的两个实体。

第 1 步 - SetTransaction(firstContext, true);

第 2 步 - 使用 firstContext 保存第一个实体。

步骤 3 - SetTransaction(secondContext, false);

第 4 步 - 使用 secondContext 保存第二个实体

第 5 步 - 最终提交事务。

void function SetTransaction(context, startNewTransaction)
{    
   var currentContext = firstContext;

   if (startNewTransaction)
   {
      var connection = currentContext.GetConnection();
      connection.Open();
      this.dbTransaction = connection.BeginTransaction();
   }

   if (this.dbTransaction != null)
   {
       currentContext.UseTransaction(dbTransaction);
   }
}

在执行步骤 3 时,currentContext.UseTransaction(dbTransaction);行抛出异常为“传入的事务与当前连接没有关联。只能使用与当前连接关联的事务

请建议如何解决。

文卡特。

【问题讨论】:

    标签: c# entity-framework-6


    【解决方案1】:

    使用TransactionScope。 EF 将自动加入正在运行的事务范围内。

    这将要求您的连接字符串相同

    using (var scope = new TransactionScope()) {
        // Save entity in context A
        using (var contextA = new ContextA()) {
            contextA.Save(...);
            contextA.SaveChanges;
        }
        // Save entity in context B
        using (var contextB = new ContextB()) {
            contextB.Save(...);
            contextB.SaveChanges;
        }
        // Commit tx-scope
        scope.Complete();
    }
    

    【讨论】:

    • 只是在管理事务的方式上相同。
    • 我猜你的意思是scope.Complete()而不是scope.Commit(),根据msdn documentation。提交方法不存在。
    • @marco 或 maarten 您能否详细说明连接字符串需要相同的方式?
    • 必须相同,否则您可能(并且很可能会)被提升为 DTC。
    • 如果上下文是在不同的方法(因此,不同的范围)中创建的,这仍然有效吗?
    【解决方案2】:

    从 EF 6 开始使用 TransactionScope is not recommanded。所以使用:

    using (var conn = new SqlConnection("..."))
            {
               conn.Open();
    
               using (var sqlTxn = conn.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
               {
                   try
                   {
                       using (var contextA = new ContextA(conn, contextOwnsConnection: false))
                        {
                            contextA.Database.UseTransaction(sqlTxn);
                            contextA.Save(...);
                            contextA.SaveChanges();
                        }
    
                        using (var contextB = new ContextB(conn, contextOwnsConnection: false))
                        {
                            contextB.Database.UseTransaction(sqlTxn);
                            contextB.Save(...);
                            contextB.SaveChanges();
                        }
    
                        sqlTxn.Commit();
                    }
                    catch (Exception)
                    {
                        sqlTxn.Rollback();
                    }
                }
            }
        }
    

    编辑: 如果您的 dbContext 没有所需的构造函数,您可以添加另一个构造函数,如下所示:

    public ContextA(): base("name=ConnectionString")
    {
    
    }
    
    public ContextA(DbConnection connection) : base(connection, false)
    {
    
    }
    

    【讨论】:

    • 这可能很好,但是在我的上下文中我找不到具有重载 ContextA(conn, contextOwnsConnection: false)); 的构造函数;我唯一的构造函数是无参数的。我正在使用 EF6!
    • 谢谢,但不像你建议的那么简单。运行时错误(太长...第 1 部分)附加信息:上下文正在 Code First 模式下使用,代码是从 EDMX 文件生成的,用于 Database First 或 Model First 开发。这将无法正常工作。要解决此问题,请不要删除引发此异常的代码行。如果您希望使用 Database First 或 Model First,请确保 Entity Framework 连接字符串包含在启动项目的 app.config 或 web.config 中。如果您正在创建自己的 DbConnection,那么
    • 错误第 2 部分:如果您正在创建自己的 DbConnection,请确保它是 EntityConnection 而不是其他类型的 DbConnection,并且您将其传递给采用的基本 DbContext 构造函数之一一个数据库连接。要了解有关 Code First、Database First 和 Model First 的更多信息,请参阅此处的实体框架文档:go.microsoft.com/fwlink/?LinkId=394715
    猜你喜欢
    • 1970-01-01
    • 2022-10-18
    • 1970-01-01
    • 2014-03-15
    • 2019-04-29
    • 1970-01-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多