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语句发生之前设置数据库名称?在构造函数中打开连接是否可行?
具有两个 DbContext 的包装器会不会开销太大?
我们最终找到了在每个 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();
}
我对项目有以下要求:使用 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语句发生之前设置数据库名称?在构造函数中打开连接是否可行?
具有两个 DbContext 的包装器会不会开销太大?
我们最终找到了在每个 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();
}