我们正在逐步用实体框架(4.3.1)替换遗留数据访问代码。在某些情况下,我们无法避免在一个工作单元中使用两种数据访问方式。理想情况下,这应该在一个事务中完成。但是,当完成一个工作单元并且EF管理自己的事务时,旧代码使用调用SqlTransaction
的{{1}}。
所以我们想到在TransactionScope
中包装“旧”和“新”代码。但是,即使Commit()
未完成,也始终会执行周围TransactionScope
内的提交。此代码段说明了我的问题:
TransactionScope
如果未using (var conn = new SqlConnection("connection string"))
{
conn.Open();
using (var scope = new TransactionScope())
{
using (var tr = conn.BeginTransaction())
{
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tr;
cmd.CommandText = "some update statement";
cmd.ExecuteNonQuery();
}
tr.Commit();
}
// In reality the code above is part of a legacy DAL, immutable.
// (can't insert SaveChanges before tr.Commit).
context.SaveChanges();
if (<all ok>) // pseudo code for exception handling.
scope.Complete();
}
}
未命中,则仍会提交更新语句 。
看来,我不能使用scope.Complete()
强制旧数据访问代码和上下文中的TransactionScope
在一个事务中执行。 或者有没有办法推翻SqlTransaction.Commit语句?
我知道这里有关于TransactionScope和SqlTransaction的更多帖子,但他们都(正确地)说使用TransactionScope时不需要(也不推荐)使用SqlTransaction。但不使用SqlTransaction不是一个选项。我们有一个遗留框架,它提交自己的SaveChanges
并且没有api可以挂钩它的事务机制。
答案 0 :(得分:7)
当未触发scope.Complete()时,仍会提交更新语句。
哦不!没有使用TransacationScope 1 。
如果在之后(或在中),则仅在
将Open
置于 TransactionScope
中应该解决此问题(即使是手动事务?),因为Connection会[通常] ]在环境TS上下文中自动登记。
现有连接可以加入环境事务范围:connection.EnlistTransaction(Transaction.Current)
。
或者,可以从现有交易创建TS,例如, new TransactionScope(transaction)
,在这里可能有用,也可能没用。
创建一个手动交易,如果完全没问题,但TS(在找到问题之后!)使处理交易更简单,更容易..至少在大多数情况下:)
快乐的编码!
1 TS未用于“更新声明”。它仍然[可能]用于context.SaveChanges()
,因为它会打开新的连接,然后自动登记。
我在上面提供了一些选项,虽然我不确定简单的“嵌套”事务。看到上下文中使用的(密封?)API可能会揭示关于限制/限制的更多见解。