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

时间:2014-08-14 11:59:40

标签: c# entity-framework-6

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

第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); line抛出异常为“传入的事务与当前连接无关。只能使用与当前连接关联的事务

请建议如何解决。

Venkat。

2 个答案:

答案 0 :(得分:32)

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

答案 1 :(得分:0)

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

}