Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实现简单数据输入应用程序的实体框架_C#_Wpf_Entity Framework - Fatal编程技术网

C# 实现简单数据输入应用程序的实体框架

C# 实现简单数据输入应用程序的实体框架,c#,wpf,entity-framework,C#,Wpf,Entity Framework,这可能已经被问了1000次,回答了1000次,但今天早上谷歌并不是我的朋友 我正在从使用存储过程和业务对象转向使用实体框架。我喜欢从生成的EDM数据库第一种方法生成POCO的简单性。而且我喜欢打字少很多 无论如何,对于我的世界中一个非常常见的应用程序场景,我很难为一个合适的设计绞尽脑汁 基本上,想象一个数据输入应用程序,比如说对于一个在线商店的管理员来说,我是用WPF做的,但它可以很容易地基于web 管理员希望在数据网格中查看“客户管理”视图中的客户列表。对于每一行,都有编辑或删除客户的按钮。在

这可能已经被问了1000次,回答了1000次,但今天早上谷歌并不是我的朋友

我正在从使用存储过程和业务对象转向使用实体框架。我喜欢从生成的EDM数据库第一种方法生成POCO的简单性。而且我喜欢打字少很多

无论如何,对于我的世界中一个非常常见的应用程序场景,我很难为一个合适的设计绞尽脑汁

基本上,想象一个数据输入应用程序,比如说对于一个在线商店的管理员来说,我是用WPF做的,但它可以很容易地基于web

管理员希望在数据网格中查看“客户管理”视图中的客户列表。对于每一行,都有编辑或删除客户的按钮。在网格的底部有一个创建新客户的按钮

如果他们删除客户,则在确认后立即从数据网格以及后端数据存储中删除该客户。如果他们编辑客户,将弹出一个窗口“编辑客户视图”,显示该客户的当前数据。他们可以编辑数据,然后单击提交或取消。提交将更改保存到数据存储,取消将放弃更改。两个按钮都关闭窗口

如果在“管理客户”视图中单击“新建客户”按钮,则会创建一个新客户对象,但尚未保存到数据库中,并打开相同的“编辑客户”视图,显示新的空白客户

以下是我到目前为止得到的信息:

构建Manage Customers视图模型时,它会填充一个公共客户列表,如:

public List<Customer> customers {get; set; }  
using (WebStoreEndities context = new WebStoreEntities())
{
    customers = context.Customers.ToList();
}
我觉得这很奇怪。我认为你不会想要一个实体实例来创建实体上下文和其他东西

问题2。在我的业务对象实现中,我缓存我的对象,所以我只需要从数据库中获取它们一次。如果他们对客户进行更改,那就太好了。我只需调用save,它就会更新数据存储。删除和插入也是如此。但是我从不需要多次获取相同的客户集合,在这个特定项目中并发性不是问题。在我的EF实现中,每次他们打开ManageCustomers视图时,都会触发上面的代码以获取客户列表。我想我可以在整个应用程序中只打开一个数据上下文,但这似乎也是一个糟糕的设计。为整个用户会话绑定数据存储的连接,仅仅因为它们可能会多次打开同一个视图

请帮我解决上述问题,如果可以的话,不要挂断我要说的话,这只是我最初的印象:

EF似乎混淆了我分离关注点的逻辑界限:

您必须在UI项目中保留实体连接字符串的副本。我通常将业务对象和数据对象保存在单独的项目中。 您不能告诉实体保存自身或删除自身。您必须从底层上下文(通常位于UI层)执行此操作。在我的UI中,我喜欢说myBusinessObject.Save或myBusinessObject.Delete,因为我知道对象知道如何保存或删除自己。 无论如何,EF似乎是未来,所以我会坚持下去。我喜欢你的推荐

非常感谢


Funk Monkey.

虽然大多数示例都是使用using来实现查询,但在您的示例中实际上不应该这样做。每个EF上下文跟踪自己的实体更改,通过使用多个using,您将不知道查找的是哪个上下文调用了SaveChanges。所以,只需为每个用户使用一个上下文,并在退出时完全释放,等等。你可以在桌面应用程序中使用单例或静态类,这似乎与我的经验没有多大区别。在MVVM场景中,ViewModel也可以处理上下文,因此当您实例化ViewModel时,实例化上下文并在dispose上处置上下文,这可能更符合逻辑,具体取决于您如何在内部处理数据

为了能够还原更改,EF实际上跟踪对象的原始DB版本以及对象的更改版本。然而,获取这些信息有点复杂:

断开连接并查找实体:

((IObjectContextAdapter)myContext).ObjectContext.Detach(dbObject);
var entry = myContext.Entry(dbObject);
var original = entry.OriginalValues;

就我个人而言,我只是处理复制和保留代码中的原始对象,它更干净,似乎更安全。它也可能更快,但我从未运行过测试来证明这一点。如果您处于多用户环境中,只需从数据库中重新加载数据,这样您就不会错误地显示过时的数据,您可能会从中受益。

问题1:您希望实体有一个保存方法,但希望避免在实体和持久层之间创建耦合,例如EF上下文?那么,如果Save方法是由 那么你无法避免。最好是将Save方法移动到存储库:

repository.Update(entity);
现在,由存储库负责创建EF上下文,而不是实体

问题2:EF上下文是轻量级的,正常的使用模式如您所描述的,即临时创建上下文,然后在保存更改后进行处理。可以想象,您可以创建一个桌面应用程序,在应用程序的生命周期中只有一个上下文,但如果在应用程序运行时更改了数据库,则上下文的内容将过时。状态的不一致性迟早会影响到您,我认为如果您坚持使用瞬态上下文模式,您会得到一个更易于维护的应用程序。如果您正在编写web应用程序,那么您将无法选择在请求之间保持数据库上下文的活动状态,并且这种模式在编写业务应用程序时已被证明是非常成功的

因此,我建议:

在存储库或服务类中实现持久性,而不是在实体类中

在读取或写入实体时,应确保EF上下文仅在操作工作单元的持续时间内存在。或者,您可以使用行版本号来确保在上次写入后,如果实体在数据库中发生了更改,则无法更新该实体


听起来…你更喜欢ActiveRecord模式…但是EF遵循UnitOfWork模式…在你的例子中,你使用的是POCO实体…它们是持久的

隐藏EF技术的一种方法是创建一个存储库层,在其中隐藏所有EF逻辑,即上下文管理。但是创建另一层可能需要大量重复性工作。通常,您的存储库将共享相同的上下文

如果保持EF上下文,那么它将为您管理已检索对象的更改跟踪和缓存


或者,您可以在断开连接的模式下工作…在该模式下,您每次要检索/perist实体时都会创建上下文…但是,在提交之前,您必须自己进行缓存和状态跟踪,并将对象重新附加到上下文。

请查看存储库和工作单元模式以使用EF。谢谢我最终选择了这条路线,这对我来说是最有意义的。它的工作真的很好!谢谢大家的帮助。无论出于何种原因,将此响应标记为答案是行不通的。也许你不喜欢狩猎。无论如何,谢谢。
repository.Update(entity);