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

Tra*_*Dev 4 c# sql-server linq-to-sql winforms

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

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

我们在VMware上运行我的工作站和服务器. - Workstation是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;
}
Run Code Online (Sandbox Code Playgroud)

笔记:

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

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

Rem*_*anu 8

我决定将此作为答案发布,而不是继续交叉评论.

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

  • 如果使用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的步骤描述MSDTC在Windows Vista和Windows Server 2008中,如何在Windows 2008上配置DTC和其他类似物品.

现在,如果你解决以下上面提到的文章,你的代码应该是工作MSDTC通信,但我仍然相信这个归档应该不是在客户端运行的代码EF发生.有更好的工具,SSIS是一个很好的例子.运行SSIS的夜间计划作业将更有效地传输这些未使用的配置文件.