错误 – 具有多个数据库连接的LINQ / TransactionScope

我有一个helluva时间将几个事务包装到同一个SQL Server上的两个不同的数据库。 我最初遇到网络DTC访问问题,我解决了这个问题。 现在,我继续得到的错误是“与底层事务管理器的通信失败了”。

我们在数据库中有一些客户配置文件,当这些配置文件过时时,我们希望将它们移动到“存档”数据库进行存储。 此举简单(幽默斜体)将它们添加到存档数据库并从主/实时数据库中删除它们。 我为每个数据库都有一个DataContext。 下面的代码执行Add,然后在尝试使用第二个DataContext时在Delete上获取错误。 我只和LINQ合作了几个月,过去几天我一直在搜索文章。 我想知道我的代码是否有任何问题,或者是否仍然没有正确配置DTC或???

我们在VMware上运行我的工作站和服务器。 – 工作站是Windows 7 SP1 – 服务器是Windows和SQL Server 2008R2

“移动”的常规:

private int MoveProfileToArchiveDB( int iProfileId ) { int rc = RC.UnknownError; // get new Archive profile object ProfileArchive.ProfileInfo piArchive = new ProfileArchive.ProfileInfo(); // 'Live' DataContext using ( ProfileDataContext dbLive = new ProfileDataContext() ) { // get Live profile ProfileInfo piLive = ProfileInfo.GetProfile( dbLive, iProfileId ); // copy Live data to Archive profile object... including the id ProfileArchive.ProfileInfo.CopyFromLive( piLive, piArchive, true ); } bool bArchiveProfileExists = ProfileArchive.ProfileInfo.ProfileExists( piArchive.id ); // make the move a transaction... using ( TransactionScope ts = new TransactionScope() ) { // Add/Update to Archive db using ( ProfileArchiveDataContext dbArchive = new ProfileArchiveDataContext() ) { // if this profile already exists in the Archive db... if ( bArchiveProfileExists ) { // update the personal profile in Archive db rc = ProfileArchive.ProfileInfo.UpdateProfile( dbArchive, piArchive ); } else { // add this personal profile to the archive db int iArchiveId = 0; piArchive.ArchiveDate = DateTime.Now; rc = ProfileArchive.ProfileInfo.AddProfile( dbArchive, piArchive, ref iArchiveId ); } // if Add/Update was successful... if ( rc == RC.Success ) { // Delete from the Live db using ( ProfileDataContext dbLive = new ProfileDataContext() ) { // delete the personal profile from the Profile DB rc = ProfileInfo.DeleteProfileExecCmd( dbLive, iProfileId ); // *** ERROR HERE *** if ( rc == RC.Success ) { // Transaction End (completed) ts.Complete(); } } } } } return rc; } 

笔记:

  1. 我有几种不同的删除方法,它们都在TransactionScope之外工作。
  2. ProfileInfo是主要的配置文件表,对于Live和Archive数据库大致相同。

任何帮助是极大的赞赏! 非常感谢…

我决定将此作为答案而不是继续交叉评论。

  • 不要使用错误代码。 这就是例外情况。 代码流更难以阅读,错误代码返回邀请被忽略。 例外使代码更易于阅读,并且更不容易出错。

  • 如果使用TransactionScope,请记住始终明确设置隔离级别。 请参阅使用新的TransactionScope()认为有害 。 SERIALIZABLE的隐式隔离级别几乎从未被要求,并且具有巨大的负面影响。

  • 交易升级。 只要在事务范围内打开多个连接,它们就可以将事务升级为分布式事务。 行为因版本而异,有些人试图将其记录下来,例如。 TransactionScope:事务升级行为 :

SQL Server 2008比SQL Server 2005更加智能,并且可以自动检测某个事务中的所有数据库连接是否指向同一物理数据库。 如果是这种情况,则事务仍为本地事务,并且不会升级为分布式事务。 不幸的是有一些警告:

  • 如果嵌套了打开的数据库连接,则事务仍会升级为分布式事务。
  • 如果在事务中,与另一个持久资源建立连接,则事务会立即升级为分布式事务。

由于您的连接(来自使用的两个数据上下文)指向不同的数据库,即使在SQL Server 2008上,您的TransactionScope也会升级到分布式事务。

将您的申请纳入DTC至少有两种方式:

  • 吞吐量将下降到最低点。 数据库每秒可以支持几千个本地事务,但每秒只能支持几十个(可能是几百个)分布式事务。 这主要是因为两阶段提交的复杂性。
  • DTC需要协调员:MSDTC。 [对MSDTC进行的安全性增强]使配置更具挑战性,并且开发人员发现在他们的应用程序中需要MSDTC当然是出乎意料的。 链接文章中描述的步骤可能就是您现在所缺少的 。 对于Windows Vista / Windows 7 / Windows Server 2008 / Windows Server 2008R2 ,Windows Vista和Windows Server 2008中的MSDTC , 如何在Windows 2008上配置DTC和其他类似文章中描述了这些步骤。

现在,如果你按照上面提到的文章修复MSDTC通信,你的代码应该正常工作,但我仍然认为这种归档不应该在运行EF的客户端代码中发生。 有更好的工具, SSIS是一个很好的例子。 运行SSIS的夜间预定作业将更有效地转移这些未使用的配置文件。