抛出异常后,我可以继续使用DbContext吗? [英] Can I continue using DbContext after it has thrown an exception?

查看:74
本文介绍了抛出异常后,我可以继续使用DbContext吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道在使用实体框架 DbContext

I'm aware of two different scenarios in which exceptions can be produced when working with an Entity Framework DbContext:


  1. 枚举查询(可能引发 EntityCommandExecutionException

  2. 调用 SaveChanges (可以抛出 DbUpdateException

  1. Enumerating a query (could throw a EntityCommandExecutionException)
  2. Calling SaveChanges (could throw a DbUpdateException)

在< href = http://msdn.microsoft.com/en-us/library/sys tem.data.entity.dbcontext%28v = vs.103%29.aspx rel = nofollow noreferrer> DbContext ,我想抓这些异常,请尝试恢复(如果适用),然后重复该操作。

Within a single instance of DbContext, I'm wanting to catch these exceptions, try to recover if applicable, and then repeat the operation.

特别是,如果调用 SaveChanges 由于死锁而引发异常,我想重试对 SaveChanges 。我已经知道如何检测这种情况并执行重试。

Specifically, if a call to SaveChanges throws an exception because of a deadlock, I would like to retry the call to SaveChanges. I already know how to detect this situation and perform the retry.

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

I saw this answer here, which indicates that an SQL connection shouldn't be used after a deadlock. This indicates that I should restart the entire DbContext and higher-level operation to recover from such exceptions.

我该做什么我不确定是否可以继续使用 DbContext 后,抛出了这样的异常。它会进入无法使用的状态吗?它仍然可以工作但不能正常运行吗?将 SaveChanges 不再在事务中发生吗?

What I'm not sure about is whether it's safe to continue using the DbContext after it has thrown an exception such as this. Will it enter an unusable state? Will it still work but not function correctly? Will SaveChanges no longer occur transactionally?

推荐答案

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

If you don't supply the DbContext with an already opened SQL connection, the DbContext will open and close the connection for you when you call SaveChanges. In that case there is no danger in keeping the DbContext around, except of course that the entities the DbContext holds on to might be in an invalid state (because this could be the reason that the SQL exception was thrown).

以下是 DbContext的示例

Here's an example of a DbContext that is suppied by an opened SQL connection and transaction:

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 在事务的上下文中运行,此答案成立。

If you supply the DbContext with a SqlConnection that runs in the context of a transaction, this answer holds.

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

Note that Entity Framework will not create a nested transaction. It simply checks whether the connection is "enlisted in user transaction". If SaveChanges already runs in a transaction, no transaction is started. Entity Framework however is unable to detect if the database has aborted the transaction because of a severe failure (such as a database deadlock). So if a first call to SaveChanges fails with something like a deadlock and you catch and recall SaveChanges, Entity Framework still thinks it is running inside a transaction.

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

This means that this second call is executed without a transaction and this means that when the operation fails halfway, the already executed statements will NOT be rolled back since there is no transaction to rollback.

b

SaveChanges 操作被破坏的问题,如果可以避免,实体框架使用嵌套事务,但仍不能解决一般的一致性问题。

The problem of the torn SaveChanges operation could have been prevented if Entity Framework used nested transactions, but it still wouldn't solve the general problem of consistency.

当我们不显式提供连接和事务时,实体框架会为我们创建连接和事务。当对 SaveChanges 的调用是更大的整体事务的一部分时,我们仅需要/希望显式提供连接和事务。因此,即使EF为我们创建了一个嵌套事务并在从 SaveChanges 返回之前提交了该事务,但是如果调用 SaveChanges 第二次,因为此嵌套事务实际上根本没有嵌套。当EF提交此嵌套事务时,实际上是提交了唯一的事务,这意味着我们需要原子化的整个操作都被破坏了; SaveChanges 完成的所有更改都将被提交,而此调用之后可能执行的操作没有运行。显然,这不是一个好地方。

Entity Framework creates connections and transactions for us when we do not supply them explicitly. We only need/want to supply a connection and transaction explicitly when the call to SaveChanges is part of a bigger overall transaction. So even if EF created a nested transaction for us and committed this before returning from SaveChanges, we're in trouble if we call SaveChanges a second time, since this 'nested' transaction actually isn't nested at all. When EF commits this 'nested' transaction, it actually commits the only transaction there is, which means that the entire operation we needed to be atomic is torn; all changes done by SaveChanges are committed, while the operations that might came after this call didn't run. Obviously this is not a good place to be.

故事的寓意在于,要么让Entity Framework为您处理连接和事务,然后就可以重做对 SaveChanges 没有风险,否则您将自己处理事务,并且在数据库引发异常时必须快速失败;您不应再调用 SaveChanges

So moral of the story is that either you let Entity Framework handle connections and transactions for you and you can redo calls to SaveChanges without risk, or you handle transactions yourself and will have to fail fast when the database throws an exception; you shouldn't call SaveChanges again.

这篇关于抛出异常后,我可以继续使用DbContext吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆