8

我们正在逐步用实体框架 (4.3.1) 替换遗留数据访问代码。在某些情况下,我们无法避免在一个工作单元中同时使用两种数据访问方式。理想情况下,这应该在一个事务中完成。但是,旧代码使用s在完成工作单元并且 EF 管理自己的事务时SqlTransaction调用。Commit()

所以我们想到将“旧”和“新”代码包装在一个TransactionScope. TransactionScope但是,即使TransactionScope未完成,始终会执行周围环境中的 Commit 。此代码段说明了我的问题:

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用来强制旧的数据访问代码和SaveChanges来自上下文的 a 在一个事务中执行。或者有没有办法推翻 SqlTransaction.Commit 语句?

我知道这里有更多关于 TransactionScope 和 SqlTransaction 的帖子,但他们都(正确地)说在使用 TransactionScope 时不需要(也不推荐)使用 SqlTransaction。但是这里不使用 SqlTransaction 不是一个选项。我们有一个遗留框架,它提交自己的SqlTransactions 并且没有 api 来挂钩其事务机制。

4

1 回答 1

9

当 scope.Complete() 没有被命中时,更新语句仍然被提交。

不好了!!未使用 TransacationScope 1

仅当连接在 TransactionScope之后(或内部)打开时,自动登记才有效。

Open 内部放入TransactionScope 应该可以解决此问题(即使使用手动事务?),因为 Connection 将 [通常] 在环境 TS 上下文中自动登记。

可以将现有连接登记到环境事务范围中:connection.EnlistTransaction(Transaction.Current).

或者,TS 可以从现有事务中创建,例如new TransactionScope(transaction),这里可能有用也可能没有帮助。

如果完全没问题,创建手动事务,但是 TS(在找出问题之后!)使处理事务变得更简单和更容易.. 至少在大多数情况下:)

快乐编码!


1 TS 未用于“更新语句”。它仍将 [可能] 用于,context.SaveChanges()因为这将打开一个连接,然后自动登记。

我在上面提供了一些选项,尽管我不确定普通的“嵌套”事务。查看上下文中使用的(密封的?)API 可能会揭示更多关于限制/限制的见解。

于 2012-07-10T19:22:33.183 回答