EntityFramework 6 和 MySql 的 TransactionScope

TransactionScope with EntityFramework 6 and MySql

我对项目有以下要求:使用 EntityFramework 在 MySql 中的多个数据库上执行事务(所有数据库都在同一台 mysql 服务器上)。

在尝试使用 TransactionScope 解决问题时,不同的 MySql 连接字符串似乎存在问题:

"Multiple simultaneous connections or connections with different connection strings inside the same transaction are not currently supported."

这里已经描述了这个问题(没有任何具体的解决方案): How do I use TransactionScope with MySql and Entity Framework? (getting Multiple simultaneous connections...are not currently supported error)

作为一种解决方法,我尝试从连接字符串中省略数据库参数,如果我在调用 .SaveChanges() 方法之前打开连接并设置数据库(通过在 class 继承自 DbContext)。但是为每个 select 语句调用相同的语句是不可行的。

我的习惯 class 看起来像这样:

public class ContextBase : DbContext
{
    public ContextBase(string connectionStringWithoutDatabase)
        : base(connectionStringWithoutDatabase)
    {}

    public override int SaveChanges()
    {
        Database.Connection.Open();
        Database.Connection.ChangeDatabase("MyDatabaseName");
        base.SaveChanges();
        Database.Connection.Close();
    }

    // How to handle Selects?
}

我的工作单位class:

public class UnitOfWork
{
    private IEnumerable<DbContext> ContextList
    {
        get { return _contextList; }
    }

    private readonly IEnumerable<DbContext> _contextList;
    public UnitOfWork(IEnumerable<DbContext> contextList)
    {
        _contextList = contextList;
    }

    public void Save()
    {
        var transactionScope = new TransactionScope();
        foreach (DbContext context in ContextList)
        {
            context.SaveChanges();
        }
        transactionScope.Complete();
        transactionScope.Dispose();
    }
}

另一种可能的解决方法是创建一个包装器,其中将有两个 DbContext 实例 - 一个为 select 语句设置数据库,另一个不为非查询操作设置数据库。但这就是感觉不对。

现在我的问题:

我们最终找到了在每个 select 之前设置数据库名称问题的解决方案。要实现这一点,必须创建一个实现 IDbCommandInterceptor 的 class 并将其注册到您的上下文中(我们在 DbContext 的构造函数中使用 this.AddInterceptor(new DatabaseSetterCommandInterceptor()); 完成了此操作)。在该界面的不同功能中,您可以在 SQL 发送到服务器之前更改数据库。 粗略测试也显示没有明显的性能下降。

我尝试使用 Devart 库。这个对我有用。 以下是我 运行.

的代码

不工作 - MySql.Data.MySqlClient.MySqlConnection

using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope(TransactionScopeOption.Required))
{
    MySql.Data.MySqlClient.MySqlConnection connect1 = new MySql.Data.MySqlClient.MySqlConnection("Server=192.168.0.1;Database=db1;Uid=root;Pwd=root;");
    MySql.Data.MySqlClient.MySqlConnection connect2 = new MySql.Data.MySqlClient.MySqlConnection("Server=192.168.0.2;Database=db2;Uid=root;Pwd=root;");
    connect1.Open();
    connect2.Open();


    var command1 = connect1.CreateCommand();
    var command2 = connect2.CreateCommand();

    command1.CommandText = "INSERT INTO test01(`Value`) VALUES(SYSDATE());";
    command2.CommandText = "INSERT INTO test02(`Value`) VALUES(SYSDATE())";

    command2.ExecuteNonQuery();
    throw new Exception("bbbbbb");
    command1.ExecuteNonQuery();

    scope.Complete();
}

正在工作 - Devart.Data.MySql.MySqlConnection

using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope(TransactionScopeOption.Required))
{
    Devart.Data.MySql.MySqlConnection connect1 = new Devart.Data.MySql.MySqlConnection("Server=192.168.0.1;Database=db1;Uid=root;Pwd=root;");
    Devart.Data.MySql.MySqlConnection connect2 = new Devart.Data.MySql.MySqlConnection("Server=192.168.0.2;Database=db2;Uid=root;Pwd=root;");
    connect1.Open();
    connect2.Open();


    var command1 = connect1.CreateCommand();
    var command2 = connect2.CreateCommand();

    command1.CommandText = "INSERT INTO test01(`Value`) VALUES(SYSDATE());";
    command2.CommandText = "INSERT INTO test02(`Value`) VALUES(SYSDATE())";

    command2.ExecuteNonQuery();
    throw new Exception("bbbbbb");
    command1.ExecuteNonQuery();

    scope.Complete();
}