简体   繁体   中英

Multiple database in one transaction in Entity Framework

I have created two different Contexts for two different databases in Entity Framework. Now I am trying to update these databases in single transaction. My code is like that:

public class LPO_BLL
{
    internal Context1 _context1 = null;
    internal Context2 _Context2 = null;

    public LPO_Detail_BLL(Context1 context1, Context2 context2)
    {
        _context1 = context1;
        _context2 = context2;
    }

    public void Insert(PM_LPO lpo, LPO_Transaction lpo_transaction)
    {
        using (TransactionScope transaction = new TransactionScope())
        {
            _context1.LPO.Add(lpo);
            _context1.SaveChanges();

            _context2.LPO_Transaction.Add(lpo_transaction);
            _context2.SaveChanges();  // I am getting error here...

            transaction.Complete();
        }
    }
}

And in UI project, I am calling this as:

LPO lpo = new LPO();
//setting properties of lpo

LPO_Transaction lpo_trans = new LPO_Transaction();
//setting properties of lpo_trans

Context1 _context1 = new Context1();
//Opening _context1 connection and etc

Context2 _context2 = new Context2();
//Opening _context2 connection and etc

LPO_BLL lpo_bll = new LPO_BLL(_context1, _context2);

lpo_bll.Insert(lpo,lpo_trans);

At the moment, I am getting error : The underlying provider failed on EnlistTransaction

After searching over the internet for last 3 hours and trying different hit and trial methods, I decided to put this on SO. So far, i have found these two links to little bit closer:

http://social.msdn.microsoft.com/Forums/en-US/3ccac6f7-6513-4c87-828a-00e0b88285bc/the-underlying-provider-failed-on-enlisttransaction?forum=adodotnetentityframework

TransactionScope - The underlying provider failed on EnlistTransaction. MSDTC being aborted

Not all DB providers support distributed transactions.

Using transaction scopes will try to enlist the DB transaction in a distributed transacation managed by MSDTC. If your provider doesn't support this, it will fail.

SQL Server and Oracle providers support distributed transactions. But many other EF providers don't.

If your DB provider doesn'd support this, you'll have to use a different one or give up using transactions.

Provided you're using SQL Server 2005, it should be working, but:

  • MSDTC service must be running (look for it in Services, in the Control Panel).
  • the connection strings must be adequate for MSDTC to work

Look at this SO Q&A: confusion about transactions and msdtc .

NOTE: The name of the service is MSDTC . So you can run net start msdtc or net stop msdtc . If you're looking for it in the control panel, you'll find a descriptive name like "Distributed Transaction Coordinator" or a localized name like "Coordinador de transacciones distribuidas". Oddly enough, there is no way to show the name column in the control panel list of local services.

You have to use ObjectContext in you DbContext in order to use SaveChanges with parameter:

public class EntityDBContext: DbContext, IObjectContextAdapter
{
    ObjectContext IObjectContextAdapter.ObjectContext {
        get { 
           return (this as IObjectContextAdapter).ObjectContext;
        }
    }
}

and then in your Insert method, use:

public void Insert(PM_LPO lpo, LPO_Transaction lpo_transaction)
{
    using (TransactionScope transaction = new TransactionScope())
    {

         context1.ObjectContext.SaveChanges(false);
         context2.ObjectContext.SaveChanges(false);

         _context1.LPO.Add(lpo);
         _context2.LPO_Transaction.Add(lpo_transaction);       

         transaction.Complete();

         context1.ObjectContext.AcceptAllChanges();
         context2.ObjectContext.AcceptAllChanges();

    }
}

For multiple database set of Savechange(false) and AcceptAllChanges() should be used.

 public void Insert(PM_LPO lpo, LPO_Transaction lpo_transaction)
{
    using (TransactionScope transaction = new TransactionScope())
    {

         context1.SaveChanges(false);
         context2.SaveChanges(false);

        _context1.LPO.Add(lpo);
        _context2.LPO_Transaction.Add(lpo_transaction);       

        transaction.Complete();

       context1.AcceptAllChanges();
       context2.AcceptAllChanges();

    }
}

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