C# 为什么 TransactionScope 不适用于实体框架?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/794707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 01:28:46  来源:igfitidea点击:

Why doesn't TransactionScope work with Entity Framework?

c#.netentity-frameworktransactionstransactionscope

提问by NotDan

See the code below. If I initialize more than one entity context, then I get the following exception on the 2nd set of code only. If I comment out the second set it works.

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

{"The underlying provider failed on Open."}

Inner: {"Communication with the underlying transaction manager has failed."}

Inner: {"Error HRESULT E_FAIL has been returned from a call to a COM component."}

{“底层提供程序在打开时失败。”}

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

内部:{“错误 HRESULT E_FAIL 已从对 COM 组件的调用返回。”}

Note that this is a sample app and I know it doesn't make sense to create 2 contexts in a row. However, the production code does have reason to create multiple contexts in the same TransactionScope, and this cannot be changed.

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

Edit

编辑

Here is a previous question of me trying to set up MS-DTC. It seems to be enabled on both the server and the client. I'm not sure if it is set up correctly. Also note that one of the reasons I am trying to do this, is that existing code within the TransactionScopeuses ADO.NET and Linq 2 Sql... I would like those to use the same transaction also. (That probably sounds crazy, but I need to make it work if possible).

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

How do I use TransactionScope in C#?

如何在 C# 中使用 TransactionScope?

Solution

解决方案

Windows Firewall was blocking the connections to MS-DTC.

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

采纳答案by Steve Willcock

Your MS-DTC (Distributed transaction co-ordinator) is not working properly for some reason. MS-DTC is used to co-ordinate the results of transactions across multiple heterogeneous resources, including multiple sql connections.

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

Take a look at this linkfor more info on what is happening.

查看此链接以获取有关正在发生的事情的更多信息。

Basically if you make sure your MS-DTC is running and working properly you should have no problems with using 2 ADO.NET connections - whether they are entity framework connections or any other type.

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

回答by NotDan

You can avoid using a distributed transaction by managing your own EntityConnection and passing this EntityConnection to your ObjectContext. Otherwise check out these.

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

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

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

回答by Denis Troller

The problem is that 2 different DataContext effectively create two different connections.

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

In that case, the transaction HAS to be promoted to a distributed transaction. I assume your problem comes from the coniguration of MS DTC (Microsoft Distributed Transaction Coordinator) on the server and or the client. If the server is not configured to allow remote connections for MSDTC for example, you will encounter that kind of exception.

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

you can refer to this MS pagefor example for troubleshooting MSDTC problems, and google is filled to the brim with articles/forum questions about it.

例如,您可以参考此 MS 页面来解决 MSDTC 问题,并且 google 充满了有关它的文章/论坛问题。

Now, it might be something else, but it really sounds like it is an MSDTC problem.

现在,它可能是别的东西,但听起来确实像是 MSDTC 问题。

回答by Davy Landman

I've written a answer in another question about how to diagnose MSDTC transactions failing.

我在另一个关于如何诊断 MSDTC 事务失败的问题中写了一个答案。

You might find that answer helpful.

您可能会发现该答案很有帮助。

How do I enable MSDTC on SQL Server?

如何在 SQL Server 上启用 MSDTC?

回答by Alex James

BTW you should consider using SaveChanges(false) in combination with AcceptChanges() when you using Explicit transactions like this.

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

That way if something fails in SaveChanges(false), the ObjectContext hasn't discarded your changes so you can re-apply later or do some error logging etc.

这样,如果 SaveChanges(false) 中的某些内容失败,则 ObjectContext 不会丢弃您的更改,因此您可以稍后重新应用或执行一些错误记录等。

See this post for more information: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx

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

Cheers

干杯

Alex

亚历克斯

回答by burnside

Add C:\Windows\msdtc.exe to the firewall exceptions on both the firewall and server. I spent ages monkeying around opening specific port numbers and ranges to no avail before I did this.

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

回答by Valdis Iljuconoks

I did have similar errors occurred when using DTC when reading messages from MQ queue, processing them and storing in SQL 2005 Express Edition database. I haven't enough time to investigate till end whether 2005 or excatly Express edition caused this problem, but switching to 2008 Standard faded that particular behavior out.

我在使用 DTC 从 MQ 队列读取消息、处理它们并存储在 SQL 2005 Express Edition 数据库中时确实发生了类似的错误。我没有足够的时间去调查到底是 2005 年还是 Express 版导致了这个问题,但是切换到 2008 标准使这种特殊行为消失了。

回答by satnhak

I'm going to stick this here because I spent 3 hours with a colleague yesterday debugging this issue. Every single answer surrounding this says that this is always a firewall issue; however in our case it wasn't. Hopefully this will spare someone else the pain.

我打算把这个贴在这里,因为我昨天和一位同事花了 3 个小时调试这个问题。围绕此问题的每一个答案都表明这始终是防火墙问题;但是在我们的情况下不是。希望这能让其他人免于痛苦。

The situation that we have is that we are currently in the process of migrating to the Entity Framework. That means that we have parts of the code where inside a single transaction connections are opened both directly using a new SqlConnection(connectionString).Open()and indirectly by using an EF data context.

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

This has been working fine in our application for a while, but when we started to retrospectively go and put tests around the code that worked in production, the code executed from the test runner kept throwing this error the first time the EF object tried to connect to the database aftera direct connection had been made in the same transaction.

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

The cause of the bug eventually turned out to be that if you do not supply an Application Name=argument to your connection string, the Entity Framework adds one by default (something like EntityFrameworkMUF). This means that you have two distinct connections in your connection pool:

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

  1. The one that you open manually with no Application Name=argument
  2. An automatically generated one suffixed Application Name=EntityFrameworkMUF
  1. 你手动打开的,没有Application Name=参数
  2. 一个自动生成的后缀 Application Name=EntityFrameworkMUF

and it is not possible to open two distinct connections inside a single transaction. The production code specified an application name; hence it worked; the test code did not. Specifying the Application Name=argument fixed the bug for us.

并且不可能在单个事务中打开两个不同的连接。生产代码指定了一个应用程序名称;因此它起作用了;测试代码没有。指定Application Name=参数为我们修复了错误。