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

时间:2013-07-18 08:28:00

标签: c#-4.0 entity-framework-5 transactionscope

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

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

请告知

提前致谢

西

1 个答案:

答案 0 :(得分:6)

使用普通DbConnection,您可以使用相同的连接字符串(使用您喜欢的任何数据库)阻止同一服务器上多个数据库的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();
}

这不会升级为DTC,但如果您为connectStr使用了不同的值,则会这样。

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

但请注意,即使使用共享连接字符串,只要您同时打开两个连接,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();
}