为什么TransactionScope不能与Entity Framework一起使用?

时间:2009-04-27 18:33:43

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

请参阅下面的代码。如果我初始化多个实体上下文,那么我在第二组代码上得到以下异常。如果我注释掉第二组它就可以了。

  

{“基础提供商在开放时失败。”}

     

内部:{“与底层事务管理器的通信失败。”}

     

Inner:{“错误HRESULT E_FAIL已从调用COM组件返回。”}

请注意,这是一个示例应用,我知道连续创建2个上下文没有意义。但是,生产代码确实有理由在同一TransactionScope中创建多个上下文,并且无法更改。

修改

以下是我尝试设置MS-DTC的上一个问题。它似乎在服务器和客户端上都启用了。我不确定它是否设置正确。另请注意,我尝试这样做的原因之一是TransactionScope中的现有代码使用ADO.NET和Linq 2 Sql ...我希望那些也使用相同的事务。 (这可能听起来很疯狂,但如果可能,我需要让它工作)。

How do I use TransactionScope in C#?

解决方案

Windows防火墙阻止了与MS-DTC的连接。

using(TransactionScope ts = new System.Transactions.TransactionScope())
        {
                using (DatabaseEntityModel o = new DatabaseEntityModel())
                {
                    var v = (from s in o.Advertiser select s).First();
                    v.AcceptableLength = 1;
                    o.SaveChanges();
                }

                //-> By commenting out this section, it works
                using (DatabaseEntityModel o = new DatabaseEntityModel())
                {
                    //Exception on this next line
                    var v = (from s1 in o.Advertiser select s1).First();                         v.AcceptableLength = 1;
                    o.SaveChanges();
                }
                //->

                ts.Complete();
        }

8 个答案:

答案 0 :(得分:19)

您可以通过管理自己的EntityConnection并将此EntityConnection传递给ObjectContext来避免使用分布式事务。否则看看这些。

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=580828&SiteID=1&mode=1 http://forums.microsoft.com/msdn/showpost.aspx?postid=113669&siteid=1&sb=0&d=1&at=7&ft=11&tf=0&pageid=1

EntityConnection conn = new EntityConnection(ConnectionString);

using (TransactionScope ts = new TransactionScope())
{
    using (DatabaseEntityModel o = new DatabaseEntityModel(conn))
    {
            var v = (from s in o.Advertiser select s).First();
            v.AcceptableLength = 1;
    }

    //-> By commenting out this section, it works
    using (DatabaseEntityModel o = new DatabaseEntityModel(conn))
    {
        //Exception on this next line
        var v = (from s1 in o.Advertiser select s1).First();
                v.AcceptableLength = 1;
    }
    //->

    ts.Complete();
}

答案 1 :(得分:19)

由于某种原因,您的MS-DTC(分布式事务协调员)无法正常工作。 MS-DTC用于协调跨多个异构资源的事务结果,包括多个sql连接。

请查看this link了解有关正在发生的事情的更多信息。

基本上,如果您确保MS-DTC正在运行并且正常工作,那么使用2个ADO.NET连接应该没有问题 - 无论它们是实体框架连接还是任何其他类型。

答案 2 :(得分:5)

将C:\ Windows \ msdtc.exe添加到防火墙和服务器上的防火墙例外。在我这样做之前,我花了很多年的时间来打开特定的端口号和范围无济于事。

答案 3 :(得分:4)

我要坚持这一点,因为我昨天和同事一起花了3个小时来调试这个问题。围绕此问题的每一个答案都表明这始终是防火墙问题;但在我们的情况下,它不是。希望这会让别人感到痛苦。

我们的情况是我们目前正在迁移到实体框架。这意味着我们有部分代码,其中单个事务连接内部使用new SqlConnection(connectionString).Open()直接打开,并通过使用EF数据上下文间接打开。

这在我们的应用程序中已经运行了一段时间,但是当我们开始回顾性地围绕在生产中工作的代码进行测试时,从测试运行器执行的代码在第一次EF对象时不断抛出此错误尝试连接到数据库 在同一事务中建立直接连接后。

错误的原因最终证明,如果您没有为连接字符串提供Application Name=参数,则实体框架默认添加一个(类似EntityFrameworkMUF)。这意味着您的连接池中有两个不同的连接:

  1. 您手动打开但没有Application Name=参数
  2. 的那个
  3. 自动生成的后缀Application Name=EntityFrameworkMUF
  4. 并且无法在单个事务中打开两个不同的连接。生产代码指定了应用程序名称;因此它有效;测试代码没有。指定Application Name=参数为我们修复了错误。

答案 4 :(得分:3)

顺便说一下,当您使用像这样的显式事务时,您应该考虑将SaveChanges(false)与AcceptChanges()结合使用。

这样,如果在SaveChanges(false)中出现问题,ObjectContext就不会丢弃您的更改,因此您可以稍后重新应用或执行一些错误记录等。

有关详情,请参阅此帖子:http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx

干杯

亚历

答案 5 :(得分:1)

问题是2个不同的DataContext有效地创建了两个不同的连接。

在这种情况下,事务HAS将被提升为分布式事务。我假设您的问题来自服务器和/或客户端上的MS DTC(Microsoft分布式事务处理协调器)的配置。 例如,如果服务器未配置为允许MSDTC的远程连接,则会遇到这种异常。

例如,您可以参考this MS page来解决MSDTC问题,并且谷歌填充了文章/论坛有关它的问题。

现在,它可能是其他东西,但它听起来确实是MSDTC问题。

答案 6 :(得分:0)

我在另一个关于如何诊断MSDTC交易失败的问题上写了一个答案。

你可能会觉得这个答案很有帮助。

How do I enable MSDTC on SQL Server?

答案 7 :(得分:0)

在从MQ队列读取消息,处理它们并存储在SQL 2005 Express Edition数据库中时,我确实发生了类似的错误。我没有足够的时间去调查,直到2005年或者激动的Express版本是否导致了这个问题,但是切换到2008 Standard已经消除了这种特殊的行为。