e36*_*6M3 5 wpf entity-framework winforms entity-framework-4
作为一个非常基本的场景,我们来看看这两个操作:
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();
}
Run Code Online (Sandbox Code Playgroud)
我只在网络项目中使用EF,并且在很大程度上依赖于网络的无状态特性.对于每个请求,我都会获得注入我的业务层外观对象(服务,管理器,无论你想要调用它们)的上下文的全新副本,所有业务经理共享同一个EF上下文实例.目前我正在开发一个WPF项目,我正在注入业务经理,然后将他们直接使用的存储库注入View Model.
让我们假设一个用户在一个复杂的屏幕上,他的第一个按钮点击调用UpdateFirstName()方法.我们假设SaveChanges()因任何原因失败.单击第二个按钮将调用InsertOrder()方法.
在Web上,这不是问题,因为操作#2的上下文与操作#1使用的上下文无关(新的http请求).但是,在桌面上,两个操作的上下文相同.问题出现在用户的名字已被修改并因此被上下文跟踪的事实中.即使原始的SaveChanges()没有采取(比如当时db不可用),调用SaveChanges()的第二个操作不仅会插入新订单,还会更新用户的名字.在几乎每一个原因中,这都是不可取的,因为用户很早就忘记了他们的第一个失败的行动.
这显然是一个愚蠢的例子,但我总是倾向于碰到这种情况,我希望我可以从每个用户操作的新上下文开始,而不是更长寿(在WPF窗口的生命周期中)例子)上下文.
你们是如何处理这些情况的?
来自直接访问数据库的临时桌面应用程序时,这是一个非常真实的询问。
似乎符合 ORM 理念的答案是拥有与屏幕具有相同生命周期的上下文。数据上下文本质上是一个工作单元实现。对于网络应用程序来说,这显然是请求并且运行良好。
对于桌面应用程序,您可以将上下文绑定到屏幕,或者可能绑定到编辑操作(在加载和按“保存”之间)。只读操作可能具有一次性上下文(必要时使用 ID 重新加载对象,例如按下网格中的“删除按钮”时)。如果您想了解其他用户的修改(关系集合在首次加载时被缓存),请忘记跨越整个应用程序生命周期的上下文。还要忘记在不同窗口之间直接共享 EF 实体,因为这实际上使其成为应用程序范围内的长期上下文。
在我看来,ORM 倾向于在桌面应用程序上强制实施类似 Web 的设计,因此。恐怕没有真正的解决办法。这本身并不是一件坏事。如果要在多个实例之间共享数据库,通常不应在桌面级别攻击数据库。在这种情况下,您将使用服务层,EF 将在其元素中,您的问题将转移到“服务上下文”......