实体框架中跨多个上下文的单个事务

本文关键字:上下文 单个 事务 框架 实体 | 更新日期: 2023-09-27 18:17:54

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

step1 - SetTransaction(firstContext, true);

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

step3 - 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);line抛出异常为"传入的事务与当前连接不关联"。"

请建议如何解决。

Venkat .

实体框架中跨多个上下文的单个事务

使用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();
}

从EF 6开始不建议使用TransactionScope。所以使用:

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)
{
}