我们有一个场景可以在单个事务中从两个上下文中保存两个实体。
第1步 - SetTransaction(firstContext,true);
步骤2 - 使用firstContext保存第一个实体。
第3步 - SetTransaction(secondContext,false);
步骤4 - 使用secondContext保存第二个实体
第5步 - 最终提交交易。
void function SetTransaction(context, startNewTransaction)
{
var currentContext = firstContext;
if (startNewTransaction)
{
var connection = currentContext.GetConnection();
connection.Open();
this.dbTransaction = connection.BeginTransaction();
}
if (this.dbTransaction != null)
{
currentContext.UseTransaction(dbTransaction);
}
}
执行第3步时,currentContext.UseTransaction(dbTransaction); line抛出异常为“传入的事务与当前连接无关。只能使用与当前连接关联的事务”
请建议如何解决。
Venkat。
答案 0 :(得分:32)
使用TransactionScope
。 EF将自动登记在正在运行的事务范围内。
这将要求您的连接字符串相同。
using (var scope = new TransactionScope()) {
// Save entity in context A
using (var contextA = new ContextA()) {
contextA.Save(...);
contextA.SaveChanges;
}
// Save entity in context B
using (var contextB = new ContextB()) {
contextB.Save(...);
contextB.SaveChanges;
}
// Commit tx-scope
scope.Complete();
}
答案 1 :(得分:0)
从EF 6开始使用TransactionScope is not recommanded。因此使用:
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var sqlTxn = conn.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
try
{
using (var contextA = new ContextA(conn, contextOwnsConnection: false))
{
contextA.Database.UseTransaction(sqlTxn);
contextA.Save(...);
contextA.SaveChanges();
}
using (var contextB = new ContextB(conn, contextOwnsConnection: false))
{
contextB.Database.UseTransaction(sqlTxn);
contextB.Save(...);
contextB.SaveChanges();
}
sqlTxn.Commit();
}
catch (Exception)
{
sqlTxn.Rollback();
}
}
}
}
编辑: 如果您的dbContext没有必需的构造函数,则可以如下添加另一个构造函数:
public ContextA(): base("name=ConnectionString")
{
}
public ContextA(DbConnection connection) : base(connection, false)
{
}