不带MS DTC的同一服务器上的多个数据库(datacontext)

Sai*_*Sai 6 transactionscope c#-4.0 entity-framework-5

我在SQL Server 2008上使用EF5.0.我在同一个服务器实例上有两个数据库.我需要更新两个数据库上的表,并希望它们是同一个事务.所以我使用了TransactionScope.以下是代码 -

public void Save()
{
        var MSObjectContext = ((IObjectContextAdapter)MSDataContext).ObjectContext;
        var AWObjectContext = ((IObjectContextAdapter)AwContext).ObjectContext;

        using (var scope = new TransactionScope(TransactionScopeOption.Required,
                                             new TransactionOptions
                                                 {
                                                     IsolationLevel = IsolationLevel.ReadUncommitted
                                                 }))
        {               
            MSObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
            AWObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);

            scope.Complete();
        }
    }
Run Code Online (Sandbox Code Playgroud)

当我使用上面的代码时,事务被提升为DTC.在互联网上搜索后,我发现这是因为两个不同的连接串/连接.但我不明白的是,如果我在一个数据库上编写存储过程,该数据库更新不同数据库中的表(在同一服务器上),则不需要DTC.那么为什么EF或TransactionScope会将其推广到DTC?还有其他的解决方法吗?

请指教

提前致谢

西

Eug*_*sky 7

使用plain DbConnections,您可以通过使用相同的连接字符串(使用您喜欢的任何数据库)来防止同一服务器上的多个数据库进行DTC升级,并手动更改打开的连接对象上的数据库,如下所示:

using (var tx = new TransactionScope())
{
    using (var conn = new SqlConnection(connectStr))
    {
        conn.Open();
        new SqlCommand("INSERT INTO atest VALUES (1)", conn).ExecuteNonQuery();
    }
    using (var conn = new SqlConnection(connectStr))
    {
        conn.Open();
        conn.ChangeDatabase("OtherDB");
        new SqlCommand("INSERT INTO btest VALUES (2)", conn).ExecuteNonQuery();
    }
    tx.Complete();
}
Run Code Online (Sandbox Code Playgroud)

这不会升级到DTC,但如果你使用不同的值,它会connectStr.

我不熟悉EF以及它如何管理连接和上下文,但使用上述见解,您可以通过执行a conn.ChangeDatabase(..)然后创建上下文来避免DTC升级new DbContext(conn, ...).

但请注意,即使使用共享连接字符串,只要您同时打开两个连接,DTC就会参与其中,就像在此修改示例中一样:

using (var tx = new TransactionScope())
{
    using (var conn = new SqlConnection(mssqldb))
    {
        conn.Open();
        new SqlCommand("INSERT INTO atest VALUES (1)", conn).ExecuteNonQuery();
        using (var conn2 = new SqlConnection(mssqldb))
        {
            conn2.Open();
            conn2.ChangeDatabase("otherdatabase");
            new SqlCommand("INSERT INTO btest VALUES (2)", conn2).ExecuteNonQuery();
        }
    }
    tx.Complete();
}
Run Code Online (Sandbox Code Playgroud)