简体   繁体   中英

Single transaction over multiple contexts in Entity Framework 6

We have a scenario to save two entities from two contexts in single transaction.

Step 1 - SetTransaction(firstContext, true);

Step 2 - Save first entity using firstContext.

Step 3 - SetTransaction(secondContext, false);

Step 4 - Save second entity using secondContext

Step 5 - finally commit the transaction.

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

While executing Step 3, currentContext.UseTransaction(dbTransaction); line throws the exception as " The transaction passed in is not associated with the current connection. Only transactions associated with the current connection may be used "

Please suggest how to resolve.

Venkat.

Use the TransactionScope . EF will automatically enlist in a running transaction-scope.

It will require that your connectionstrings are identical .

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

Using TransactionScope is not recommanded from EF 6 onward. So use:

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

Edit: If your dbContext does not have required constructor, You can add another constructor as follow:

public ContextA(): base("name=ConnectionString")
{

}

public ContextA(DbConnection connection) : base(connection, false)
{

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM