TransactionScope与EntityFramework 6和MySql

时间:2015-03-02 09:57:13

标签: mysql .net transactions entity-framework-6

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

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

  

“目前不支持在同一事务中使用不同连接字符串的多个同时连接或连接。”

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

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

我的自定义类看起来像这样:

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?
}

我的工作单位:

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语句出现之前设置数据库名称?在构造函数中打开连接是否可行?

  • 带有两个DbContexts的包装器是否会过多开销?

2 个答案:

答案 0 :(得分:1)

我们最终找到了解决在每次选择之前设置数据库名称的问题。要实现这一点,必须创建一个实现IDbCommandInterceptor的类,并将其注册到您的上下文中。在该接口的不同功能中,您可以在将SQL发送到服务器之前更改数据库。 粗略的测试也没有显示出明显的性能下降。

答案 1 :(得分:1)

我尝试使用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();
}