14

我知道在使用实体框架时可能会产生异常的两种不同情况DbContext

  1. 枚举一个查询(可以抛出一个EntityCommandExecutionException
  2. 调用SaveChanges(可以抛出一个DbUpdateException

在 的单个实例中DbContext,我想捕获这些异常,如果适用,尝试恢复,然后重复操作。

具体来说,如果调用SaveChanges由于死锁而引发异常,我想重试调用SaveChanges. 我已经知道如何检测这种情况并执行重试。

我在这里看到了这个答案,这表明死锁后不应使用 SQL 连接。这表明我应该重新启动整个DbContext更高级别的操作以从此类异常中恢复。

我不确定的是DbContext在抛出诸如此类的异常之后继续使用是否安全。它会进入无法使用的状态吗?它仍然可以工作但不能正常工作吗?将SaveChanges不再以交易方式发生?

4

1 回答 1

6

如果您不提供DbContext已打开的 SQL 连接,则DbContext当您调用SaveChanges. 在这种情况下,保持周围没有任何危险DbContext,当然,除了DbContext持有的实体可能处于无效状态(因为这可能是引发 SQL 异常的原因)。

这是一个DbContext由打开的 SQL 连接和事务提供的示例:

using (var connection = new SqlConnection("my connection"))
{
    connection.Open();

    using (var transaction = connection.BeginTransaction())
    {
        using (var context = new DbContext(connection))
        {
            // Do useful stuff.

            context.SaveChanges();
        }

        transaction.Commit();
    }
}

如果您提供在事务上下文中运行的 a,则DbContext答案成立。SqlConnection

请注意,实体框架不会创建嵌套事务。它只是检查连接是否“在用户事务中登记”。如果SaveChanges已经在事务中运行,则不会启动事务。但是,Entity Framework 无法检测数据库是否由于严重故障(例如数据库死锁)而中止了事务。因此,如果第一次调用SaveChanges失败并出现死锁之类的问题,并且您捕获并回忆SaveChanges,Entity Framework 仍然认为它在事务中运行。

这意味着第二次调用在没有事务的情况下执行,这意味着当操作中途失败时,已经执行的语句将不会回滚,因为没有事务可以回滚。

如果 Entity Framework 使用嵌套事务,则可以防止撕裂SaveChanges操作的问题,但它仍然不能解决一般的一致性问题。

当我们没有明确提供它们时,实体框架会为我们创建连接和事务。SaveChanges当调用是更大的整体事务的一部分时,我们只需要/想要明确地提供连接和事务。因此,即使 EF 为我们创建了一个嵌套事务并在从 返回之前提交了它SaveChanges,如果我们第二次调用,我们也会遇到麻烦SaveChanges,因为这个“嵌套”事务实际上根本没有嵌套。当 EF 提交这个“嵌套”事务时,它实际上提交了唯一的事务,这意味着我们需要成为原子的整个操作都被破坏了;by 完成的所有更改SaveChanges都已提交,而在此调用之后可能发生的操作未运行。显然,这不是一个好去处。

这个故事的寓意是,要么让 Entity Framework 为你处理连接和事务,你可以SaveChanges毫无风险地重做调用,或者你自己处理事务,当数据库抛出异常时必须快速失败;你不应该再打电话SaveChanges了。

于 2013-10-01T08:38:37.543 回答