抛出异常后,我可以继续使用DbContext吗? [英] Can I continue using DbContext after it has thrown an exception?
问题描述
我知道在使用实体框架 DbContext
:
I'm aware of two different scenarios in which exceptions can be produced when working with an Entity Framework DbContext
:
- 枚举查询(可能引发
EntityCommandExecutionException
) - 调用
SaveChanges
(可以抛出DbUpdateException
)
- Enumerating a query (could throw a
EntityCommandExecutionException
) - Calling
SaveChanges
(could throw aDbUpdateException
)
在< 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 $ c,我们也会遇到麻烦$ c>第二次,因为此嵌套事务实际上根本没有嵌套。当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屋!