【问题标题】:How to run two Entity Framework Contexts inside TransactionScope without MSDTC?如何在没有 MSDTC 的情况下在 TransactionScope 中运行两个实体框架上下文?
【发布时间】:2010-03-03 10:38:08
【问题描述】:

这个问题在这里的一个简单示例中不容易重现,但想知道是否有人有任何经验和提示,这里是问题:

  • 使用实体框架
  • 在应用程序中有很多点,其中 (1) 数据被写入某些 entity 表,例如客户,(2) 数据写入history
  • 这两个操作都使用实体框架,但是,它们使用不同的上下文
  • 这些操作需要在一个事务中:即,如果一个无法写入,另一个不应写入,等等。
  • 我可以用 TransactionScope 包装它们,

像这样:

using (TransactionScope txScope = new TransactionScope()) {
    ...
}

但这给了我:

Microsoft 分布式事务处理协调器 (MSDTC) 被禁用 网络交易。

我们的数据库管理员告诉我,MSDTC 被选择禁用并且无法安装

因此,我正在尝试使用 MetadataWorkspace 创建我自己的 EntityConnection,并且我的想法是每个上下文都将使用相同的 EntityConnection。然而,事实证明,试图让它发挥作用几乎是不可能的,例如目前我继续收到上述错误,即使理论上两个上下文都使用 EntityConnection。例如,很难理解实体框架在哪里/为什么需要 MSDTC。

有没有人曾经走过这条路,有经验或代码示例可以分享?

【问题讨论】:

    标签: entity-framework transactions msdtc


    【解决方案1】:

    嗯,这个问题很简单。

    如果您使用的是 sql server 2008,您应该不会遇到这个问题,因为您有可升级的事务,并且 .NET 知道您使用的是相同的持久性存储(数据库),它不会将其提升到 DTC 并将其作为本地提交. look into promotable transaction with sql server 2008.

    据我所知,Oracle 正在其驱动程序中工作以支持可升级事务,但我不知道状态,MS oracle 驱动程序不支持它。 http://www.oracle.com/technology/tech/windows/odpnet/col/odp.net_11.1.0.7.20_twp.pdf

    如果您使用的驱动程序不支持可升级事务,则 .NET 无法使用本地事务进行两个连接。您应该更改架构或说服数据库管理员安装 MSDTC。

    【讨论】:

    • hmmm,我们实际上使用的是 SQL Server 2008,它似乎实际上并不知道我们在两个连接中使用相同的数据库:因此我目前的方法是构建两个 EntityConnection 对象,都来自一个SqlConnection 对象,也许这些 SQLConnection 对象在两个上下文中都是相同的,EF 不会将其提升为 DTC。
    • 更新:抱歉,数据库实际上仍然是 SQL Server 2005,正如您所指出的,这似乎是问题所在,在阅读了这篇包含大量记录数据的最优秀帖子后,我仔细检查了版本,因为他解决了这个问题:stackoverflow.com/questions/1690892/…
    • 所以最后你有两个选择:将 sqlserver 更改为 2008 或更改代码。祝你好运!
    【解决方案2】:

    我在使用 SQL 2008 实体框架时遇到了类似的问题。

    我定义了两个框架(EF1 和 EF2),但使用相同的连接字符串连接到 sql 2008 数据库。

    当在两者中使用嵌套的“usings”时,我得到了上面的 MSDTC 错误。 例如代码是这样的:

    using (TransactionScope dbContext = new TransactionScope())
    {
         using (EF1 context = new EF1())
         {
             // do some EF1 db call
             using (EF2 context2 = new EF2())
             {
                  // do some EF2 db call
              }
          }
          dbContext.Complete();
    }
    

    它没有这么简单,因为它被分成了几个方法,但这是“使用”的基本结构。

    解决方法是一次只打开一个使用。没有 MTDSC 错误,无需在 db 上打开分布式事务。

    using (TransactionScope dbContext = new TransactionScope())
    {
         using (EF1 context = new EF1())
         {
             // do some EF1 db call
    
          }
         using (EF2 context2 = new EF2())
         {
                  // do some EF2 db call
         }
         dbContext.Complete();
    }
    

    【讨论】:

    • 是的,这段代码不起作用。它与调用每个产生不同上下文的方法没有什么不同。
    • TransactionScope 不再是在 EF 6 上管理事务的推荐方法。我知道您在写答案时考虑了 EF1 和 EF2,但我只是想指出,现在我们不应该使用事务范围。请参阅 Microsoft 的此链接:msdn.microsoft.com/en-us/data/dn456843.aspx
    • @FranciscoGoldenstein Fair,但dbContext.Database.BeginTransaction() 仅适用于您使用单个上下文并且它已经打开的情况。这是您链接的文章地址的唯一情况。它不适用于更复杂的条件。
    【解决方案3】:

    我认为您需要做的是强制您的上下文共享单个数据库连接。然后,您将能够在单个事务中针对两个不同的上下文执行这两个操作。您可以通过将一个 EntityConnection 对象传递给上下文的两个构造函数来实现这一点。当然,这种方法需要您将此对象传递给更新数据库的方法。

    我最近blogged 谈到了创建数据库上下文范围,这将使使用多个 EF 上下文和事务更容易。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-03
      • 2018-09-22
      相关资源
      最近更新 更多