为什么 TransactionScope 不能与实体框架一起使用?
请参阅下面的代码。 如果我初始化多个实体上下文,则仅在第二组代码上出现以下异常。 如果我注释掉第二组它就有效。
{“底层提供程序在打开时失败。”}
内部:{“与底层事务管理器的通信失败。”}
内部:{“调用 COM 组件已返回错误 HRESULT E_FAIL。”}
请注意,这是一个示例应用程序,我知道连续创建 2 个上下文是没有意义的。 但是,生产代码确实有理由在同一个 TransactionScope
中创建多个上下文,并且这是无法更改的。
编辑
这是我之前尝试设置 MS-DTC 的问题。 它似乎在服务器和客户端上均启用。 我不确定它是否设置正确。 另请注意,我尝试执行此操作的原因之一是 TransactionScope
中的现有代码使用 ADO.NET 和 Linq 2 Sql...我希望它们也使用相同的事务。 (这可能听起来很疯狂,但如果可能的话我需要让它发挥作用)。
解决方案
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();
}
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."}
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.
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 TransactionScope
uses 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).
How do I use TransactionScope in C#?
Solution
Windows Firewall was blocking the connections to 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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您的 MS-DTC(分布式事务协调器)由于某种原因无法正常工作。 MS-DTC 用于协调跨多个异构资源(包括多个 SQL 连接)的事务结果。
查看此链接< /a> 了解有关正在发生的事情的更多信息。
基本上,如果您确保 MS-DTC 正在运行并正常工作,那么使用 2 个 ADO.NET 连接应该不会有任何问题 - 无论它们是实体框架连接还是任何其他类型。
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.
Take a look at this link for 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.
您可以通过管理自己的 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
You can avoid using a distributed transaction by managing your own EntityConnection and passing this EntityConnection to your ObjectContext. Otherwise check out these.
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
将 C:\Windows\msdtc.exe 添加到防火墙和服务器上的防火墙例外中。 在我这样做之前,我花了很长时间来打开特定的端口号和范围,但没有成功。
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.
我将把它放在这里,因为昨天我和一位同事花了 3 个小时来调试这个问题。 围绕这个问题的每个答案都表明这始终是防火墙问题; 但在我们的例子中却并非如此。 希望这能让其他人免受痛苦。
我们的情况是,我们目前正在迁移到实体框架。 这意味着我们有部分代码在单个事务内部直接使用 new SqlConnection(connectionString).Open() 和间接使用 EF 数据上下文打开连接。
这在我们的应用程序中运行良好一段时间了,但是当我们开始回顾性地对生产中运行的代码进行测试时,从测试运行器执行的代码在 EF 对象第一次尝试连接时不断抛出此错误在同一事务中建立直接连接之后到数据库。
该错误的原因最终被证明是,如果您没有向连接字符串提供
Application Name=
参数,实体框架会默认添加一个(类似于EntityFrameworkMUF
>)。 这意味着您的连接池中有两个不同的连接:Application Name=
参数的情况下手动打开的连接Application Name=EntityFrameworkMUF
的连接不可能在单个事务中打开两个不同的连接。 生产代码指定了应用程序名称; 因此它起作用了; 测试代码没有。 指定
Application Name=
参数为我们修复了该错误。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.
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.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 after a direct connection had been made in the same transaction.
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 likeEntityFrameworkMUF
). This means that you have two distinct connections in your connection pool:Application Name=
argumentApplication 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.顺便说一句,当您使用这样的显式事务时,您应该考虑将 SaveChanges(false) 与 AcceptChanges() 结合使用。
这样,如果 SaveChanges(false) 中出现故障,ObjectContext 不会放弃您的更改,因此您可以稍后重新应用或进行一些错误日志记录等。
有关详细信息,请参阅此文章:http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges- false.aspx
干杯
亚历克斯
BTW you should consider using SaveChanges(false) in combination with AcceptChanges() when you using Explicit transactions like this.
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.
See this post for more information: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx
Cheers
Alex
问题是 2 个不同的 DataContext 有效地创建了两个不同的连接。
在这种情况下,事务必须提升为分布式事务。 我假设您的问题来自服务器和/或客户端上的 MS DTC(Microsoft 分布式事务协调器)的配置。
例如,如果服务器未配置为允许 MSDTC 远程连接,您将遇到此类异常。
您可以参考此 MS 页面来解决 MSDTC 问题,谷歌充满了有关它的文章/论坛问题。
现在,可能是别的问题,但听起来确实是 MSDTC 问题。
The problem is that 2 different DataContext effectively create two different connections.
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.
you can refer to this MS page for example for troubleshooting MSDTC problems, and google is filled to the brim with articles/forum questions about it.
Now, it might be something else, but it really sounds like it is an MSDTC problem.
我在另一个问题中写了一个关于如何诊断 MSDTC 事务失败的答案。
您可能会发现这个答案很有帮助。
如何在 SQL Server 上启用 MSDTC?
I've written a answer in another question about how to diagnose MSDTC transactions failing.
You might find that answer helpful.
How do I enable MSDTC on SQL Server?
当我使用 DTC 从 MQ 队列读取消息、处理它们并将其存储在 SQL 2005 Express Edition 数据库中时,确实发生了类似的错误。 我没有足够的时间来调查到底是 2005 还是 Express 版本导致了这个问题,但是切换到 2008 Standard 就消除了这个特定的行为。
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.