C# 正确处理DbUpdateConcurrencyException

C# 正确处理DbUpdateConcurrencyException,c#,winforms,entity-framework-6,visual-studio-2017,optimistic-concurrency,C#,Winforms,Entity Framework 6,Visual Studio 2017,Optimistic Concurrency,这是关于DBContext生存期的文档: 当使用Windows演示基础(WPF)或Windows时 窗体,则为每个窗体使用上下文实例。这允许您使用 更改上下文提供的跟踪功能 我已经读到DBContext的生存期应该尽可能短,但显然在WinForms(我正在使用)的情况下,这个规则不适用,建议使用其他规则 当前设置 另外,我的应用程序遵循MVC模式,在我的控制器中,我初始化了DBContext。现在,当表单关闭时,除其他事项外,控制器实例也被释放,这就是上下文终止的地方。如果有必要的话,我也使用数

这是关于DBContext生存期的文档:

当使用Windows演示基础(WPF)或Windows时 窗体,则为每个窗体使用上下文实例。这允许您使用 更改上下文提供的跟踪功能

我已经读到
DBContext
的生存期应该尽可能短,但显然在
WinForms
(我正在使用)的情况下,这个规则不适用,建议使用其他规则

当前设置

另外,我的应用程序遵循
MVC
模式,在我的控制器中,我初始化了
DBContext
。现在,当表单关闭时,除其他事项外,控制器实例也被释放,这就是上下文终止的地方。如果有必要的话,我也使用数据库优先的方法

现在总是打开一个上下文(每个表单)似乎有它自己的便利(你可以很容易地跟踪上下文的变化),但例如,我发现自己(作为
EF
初学者)有些怀疑。。。看看这种情况:

我有
IList
用户(用户实体),在创建表单时初始化。我运行了两个(甚至更多)应用程序实例,因为它要在多用户环境中工作。现在,假设用户A和用户B都加载相同的记录(用户管理屏幕,所以他们都是管理员)。。。现在当事情发展到这样的地步:

用户
A
对某些记录进行更改(更新) 用户
B
对同一记录进行更改(更新),并将其保存到数据库中 用户
A
尝试保存 将引发一个
DbUpdateConcurrencyException

现在这很好,我知道一个术语乐观并发,并且说用户
a
B
都在更新同一行(或同一列),我会处理这样的异常(如果我缺少什么,请更正我):

现在这似乎起作用了。。。因为只要表单处于活动状态,我的上下文就会打开,所以当我在ex.Entries.Single()上重新加载()时,列表中的特定用户(请记住,我以前提到过一个用户列表)会用实际的数据库值刷新,因此当我重新加载视图时,用户会获得当前状态

实际问题

到目前为止还不错……但例如在这种情况下:

用户
A
删除该行

用户
B
尝试更新并保存同一行(已删除行)上的更改

我遇到了很多问题,我不知道什么是正确的处理方法

我想,我应该更新用户列表,但不知道如何在不处理当前上下文的情况下进行更新。所以这将是一个问题。。。如何从数据库重新加载用户列表,而不在此代码块中处理上下文:

catch (DbUpdateConcurrencyException ex)
{
    // Reload the user list with navigation properties fully initialized (note that user list is what would context.korisnik.ToList() would return)
    // Reload the UI
}

在这种情况下,处理乐观并发错误的正确方法是什么?

您可以使用寿命较短的上下文,或者在上下文无效时(即遇到并发异常)处理上下文并重新创建它。对于UI,您可能应该显示一条错误消息,并且只允许用户关闭表单或重新加载内容(使用新的DbContext实例)。这将使他们有机会在重新加载/退出之前复制/记录他们想要提交的更改。@Igor我已经想到了这一点(在抛出并发异常时重新创建上下文)。我必须试一试。此外,对于投票决定关闭的人来说……这个问题的答案不属于基于意见的类别,因为我问的是如何在不关闭上下文的情况下重新加载
上下文。用户
使用数据库值,我问的是有关此实现的一些想法…您可以将实体从
DbContext
中冷分离,然后再次尝试检索它(如果它存在,即它不是删除)。@Igor当我重新加载时();删除的行(实体)已分离。。。或者我不明白你说的?我所做的是重新初始化上下文和用户列表,并重新加载UI,使其按我所希望的方式工作。。。但是,我仍然想知道,在不重新创建新上下文的情况下,什么是正确的处理方法……这就是我的意思,将现在删除的实体从现有的
DbContext
中分离出来。
catch (DbUpdateConcurrencyException ex)
{
    // Reload the user list with navigation properties fully initialized (note that user list is what would context.korisnik.ToList() would return)
    // Reload the UI
}