这可能已经被要求并回答了1000次,但是今天上午Google并不是我的朋友。
我正在从使用存储过程和业务对象切换到使用实体框架。我喜欢从生成的EDM(此处为数据库优先方法)生成POCO的简便性。我喜欢打字少了多少。
我很难为非常普通的应用场景(无论如何,在我的世界中)选择合适的设计来解决问题。
基本上,想象一个数据输入应用程序,比方说一个在线商店的管理员(我在WPF中这样做,但它很容易基于Web)。
管理员将要在数据网格中查看客户列表(“管理客户”视图)。对于每一行,都有一个按钮来编辑客户或将其删除。在网格的底部,有一个用于创建新客户的按钮。
如果他们删除客户,则将其(在确认后)立即从数据网格以及后端数据存储中删除。如果他们编辑客户,则会弹出一个窗口(“编辑客户视图”),显示该客户的当前数据。他们可以编辑数据,然后单击“提交”或“取消”。提交将更改保存到数据存储中,而取消则放弃更改。两个按钮都关闭窗口。
如果他们从“管理客户”视图中单击“新客户”按钮,则会创建一个新的“客户”对象(尚未保存到数据库),并打开相同的“编辑客户”视图,显示新的空白客户。
这是到目前为止我得到的:
构建“管理客户”视图模型时,它将填充“客户”的公共列表,例如:
public List<Customer> customers {get; set; }
using (WebStoreEndities context = new WebStoreEntities())
{
customers = context.Customers.ToList();
}
然后,如果管理员用户单击“客户”行中的“编辑”按钮,则绑定的“客户”对象将传递到“编辑客户”视图的构造函数。该视图构造其视图模型,该模型具有该视图绑定到的客户属性。用户可以在视图中对“客户”对象进行更改,然后单击“保存”或“取消”。
这是我迷路的地方。在我的业务对象/存储过程实现中,我只有两个Customer对象:一个用于正在编辑的Customer(绑定到视图),以及该Customer的一个副本,称为backupCustomer,如果它们从菜单中取消,则用于还原更改。编辑客户视图(由于我使用的是MVVM,因此客户的属性会立即从UI更改,并且如果他们开始进行更改,然后单击“取消”,则他们希望在该客户中看不到他们的更改)。
更重要的是,如果他们确实单击“编辑客户”视图中的“提交”,则会调用“客户”业务对象的Save()方法,该方法将进入DAL并触发存储过程以更新数据存储。
好的,现在进入实体框架现实。
第1期。无法保存单个实体。因此,即使我将Customer实体扩展为具有Save()方法,它也必须创建一个新的WebStoreEntities上下文并在其上调用SaveChanges():
using (WebStoreEntities context = new WebStoreEntities())
{
context.SaveChanges();
}
对我来说这很奇怪。我认为您不希望有一个实体实例来创建实体上下文和东西。
第2期。在我的业务对象实现中,我缓存了对象,因此只需要一次从数据库中获取它们。如果他们对客户做出改变,那就太好了。我只是在上面调用save(),它会更新数据存储。与删除和插入相同。但是,我从来不需要多次获取相同的客户集合(并发不是这个特定项目的问题)。在我的EF实施中,每次他们打开“管理客户”视图时,都会触发上面的代码以获取“客户”列表。我想我可以在整个应用程序中保持一个数据上下文打开,但这似乎也是一个糟糕的设计。在整个用户会话中为数据存储建立连接,只是因为他们可能多次打开同一视图。
请为我解决上述问题,如果可以的话,请不要挂断我要说的话(无论如何,这只是我的最初印象):
似乎EF混淆了我分离关注点时的逻辑界限:
无论如何,EF似乎是未来,所以我会坚持下去。我很乐意您的建议。
非常感谢!
放克猴子。
虽然大多数示例都实现了用a包围的查询,using
但实际上您不应该这样做。每个EF上下文通过使用多个跟踪它自己的实体更改,using
您将不知道是在哪个上下文中进行了调用SaveChanges
。因此,仅对每个用户使用一个上下文,并在完成操作后(退出时等)进行处理。您可以使用单例或静态类,在桌面应用程序中,这与我的经验似乎并没有多大区别。在MVVM场景中,您也许也可以摆脱使用ViewModel处理上下文的麻烦,因此,当实例化ViewModel时,实例化上下文并将上下文处置为dispose,这可能在逻辑上更有意义,具体取决于您内部处理数据的方式。
为了能够还原更改,EF实际上会跟踪对象的原始DB版本以及更改后的对象版本。但是,要获取这些信息有些费解:
断开连接并查找实体:
((IObjectContextAdapter)myContext).ObjectContext.Detach(dbObject);
var entry = myContext.Entry(dbObject);
var original = entry.OriginalValues;
就我个人而言,我只负责复制原始对象并将其保留在代码中,它更干净,而且似乎更安全。它可能也更快,但是我从来没有运行测试来证明这一点。如果您在多用户环境中,则可能会从简单地从数据库重新加载数据中受益,从而不会误显示陈旧数据。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句