长期存在的实体框架上下文 - 避免数据完整性问题的最佳实践

2024-01-02

作为一个非常基本的场景,我们来看这两个操作:

UserManager.UpdateFirstName(int userId, string firstName)
{
    User user = userRepository.GetById(userId);
    user.FirstName = firstName;
    userRepository.SaveChanges();
}

InventoryManager.InsertOrder(Order newOrder)
{
    orderRepository.Add(newOrder);
    orderRepository.SaveChanges();
}

我只在 Web 项目中使用过 EF,并且严重依赖于 Web 的无状态特性。对于每个请求,我都会获得注入到我的业务层外观对象(服务、管理器,无论您想如何称呼它们)中的上下文的新副本,所有业务管理器共享 EF 上下文的同一实例。目前我正在开发一个 WPF 项目,我将业务管理器以及随后他们直接使用的存储库注入到视图模型中。

假设用户位于复杂的屏幕上,并且他的第一次按钮单击调用了 UpdateFirstName() 方法。让我们假设 SaveChanges() 由于某种原因失败。他们的第二次单击按钮将调用 InsertOrder() 方法。

在网络上,这不是问题,因为操作 #2 的上下文与操作 #1 使用的上下文不相关(新的 http 请求)。然而,在桌面上,这两个操作的上下文相同。问题的出现是因为用户的名字已被修改,因此会被上下文跟踪。即使最初的 SaveChanges() 没有执行(假设数据库当时不可用),调用 SaveChanges() 的第二个操作不仅会插入新订单,还会更新用户的名字。几乎在所有原因中,这都是不可取的,因为用户早已忘记了他们的第一个操作无论如何都失败了。

这显然是一个愚蠢的例子,但我总是倾向于遇到这样的场景,我希望我可以为每个用户操作重新开始一个新的上下文,而不是拥有更长的生命周期(对于 WPF 窗口的生命周期)示例)上下文。

你们如何处理这些情况?


来自直接访问数据库的临时桌面应用程序时,这是一个非常真实的询问。

似乎符合 ORM 理念的答案是拥有与屏幕具有相同生命周期的上下文。 数据上下文本质上是一个工作单元实现。对于网络应用程序来说,这显然是请求并且运行良好。

对于桌面应用程序,您可以将上下文绑定到屏幕,或者可能绑定到编辑操作(在加载和按“保存”之间)。只读操作可能具有一次性上下文(必要时使用 ID 重新加载对象,例如按下网格中的“删除按钮”时)。 如果您想随时了解其他用户的修改(关系集合在首次加载时会被缓存),请忘记跨越整个应用程序生命周期的上下文。 还要忘记在不同窗口之间直接共享 EF 实体,因为这实际上使其成为应用程序范围内的长期上下文。

在我看来,ORM 倾向于在桌面应用程序上强制实施类似 Web 的设计,因此。恐怕没有真正的解决办法。 这本身并不是一件坏事。如果要在多个实例之间共享数据库,通常不应在桌面级别攻击数据库。在这种情况下,您将使用服务层,EF 将在其元素中,您的问题将转移到“服务上下文”......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

长期存在的实体框架上下文 - 避免数据完整性问题的最佳实践 的相关文章

随机推荐