【问题标题】:Multiple database in one transaction in Entity Framework实体框架中的一个事务中的多个数据库
【发布时间】:2013-12-09 10:27:24
【问题描述】:

我在实体框架中为两个不同的数据库创建了两个不同的上下文。现在我正在尝试在单个事务中更新这些数据库。我的代码是这样的:

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

在 UI 项目中,我将其称为:

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

目前,我收到错误: 基础提供商在 EnlistTransaction 上失败

在互联网上搜索了最后 3 个小时并尝试了不同的点击和试用方法后,我决定将它放在 SO 上。到目前为止,我发现这两个链接更接近一点:

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

【问题讨论】:

    标签: c# asp.net .net entity-framework transactions


    【解决方案1】:

    并非所有数据库提供者都支持分布式事务。

    使用事务作用域将尝试在由 MSDTC 管理的分布式事务中登记数据库事务。如果您的提供者不支持这一点,它将失败。

    SQL Server 和 Oracle 提供程序支持分布式事务。但许多其他 EF 提供商却没有。

    如果您的数据库提供商不支持这一点,您将不得不使用不同的或放弃使用事务。

    如果您使用的是 SQL Server 2005,它应该可以工作,但是:

    • MSDTC 服务必须正在运行(在“服务”中的“控制面板”中查找)。
    • 连接字符串必须足以让 MSDTC 工作

    this SO Q&A: confusion about transactions and msdtc

    注意:服务的名称是MSDTC。所以你可以运行net start msdtcnet stop msdtc。如果您在控制面板中查找它,您会找到一个描述性名称,如“分布式事务协调器”或一个本地化名称,如“Coordinador de transacciones distribuidas”。奇怪的是,没有办法在本地服务的控制面板列表中显示名称列。

    【讨论】:

    • 我使用 SQL Server 2005 作为两个上下文的提供程序。
    • MSDTC 正在运行吗?您是如何创建连接字符串的?
    • 我在 Application_Start 事件中的 Global.ascx 中创建连接字符串。而且我不知道 MSDTC 是否正在运行?
    • 我刚刚检查过了。我们的服务器上启用了 MSDTC。
    • SQL server 和 app server 是不同的机器吗?查找 MSDTC 配置。有一些事情需要考虑(网络连接、在客户端和服务器上运行的 MSDTC 以及其他一些事情)。查看异常堆栈(内部异常),看看是否有任何消息可以澄清问题。
    【解决方案2】:

    您必须在 DbContext 中使用 ObjectContext 才能使用带有参数的 SaveChanges:

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

    然后在您的 Insert 方法中,使用:

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

    【讨论】:

      【解决方案3】:

      对于多个数据库集,应使用 Savechange(false) 和 AcceptAllChanges()。

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

      【讨论】:

      • 我使用的是 Entity Framework 5,没有可以接受任何参数的 SaveChanges 方法。
      • 这是个好方法,但我不知道为什么我的应用程序不支持 SaveChanges(false)。我正在使用实体框架 5。
      • 我不确定,但请参阅 EF5 的文档或尝试使用以前的版本。
      • Usman 使用这个 SaveChanges(SaveOptions.DetectChangesBeforeSave) 相当于 SaveChanges(false)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多