抛出异常后,我可以继续使用DbContext吗?

时间:2013-10-01 05:33:48

标签: entity-framework entity-framework-5

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

  1. 枚举查询(可以抛出EntityCommandExecutionException
  2. 致电SaveChanges(可以抛出DbUpdateException
  3. DbContext的单个实例中,我想要捕获这些异常,尝试恢复(如果适用),然后重复操作。

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

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

    我不确定的是,在引发此类异常之后继续使用DbContext是否安全。它会进入无法使用状态吗?它仍然可以工作但功能不正确吗?事件SaveChanges不会再发生了吗?

1 个答案:

答案 0 :(得分:6)

如果您未向DbContext提供已打开的SQL连接,则DbContext会在您拨打SaveChanges时打开并关闭连接。在这种情况下,保持DbContext没有危险,当然DbContext所持有的实体可能处于无效状态(因为这可能是SQL异常的原因)抛出)。

以下是打开的SQL连接和事务所提供的DbContext示例:

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();
    }
}

如果您为DbContext提供了在交易环境中运行的SqlConnection,则this answer成立。

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

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

如果Entity Framework使用嵌套事务,则可能会阻止SaveChanges操作被破坏的问题,但它仍然无法解决一致性的一般问题。

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

故事的寓意在于,要么让Entity Framework为您处理连接和事务,您可以无风险地重做对SaveChanges的调用,或者您自己处理事务,并且在数据库抛出时必须快速失败例外;你不应该再次致电SaveChanges