Answers:
如果您想知道对WPF / WinForm应用程序单个对象上下文有什么影响,请查阅本文。它与NHibernate Session有关,但是想法是相同的。
编辑:
使用EF时,默认情况下,每个上下文仅加载每个实体一次。第一个查询创建实体实例并将其存储在内部。任何随后的需要实体具有相同键的查询都将返回此存储的实例。如果数据存储中的值发生更改,您仍然会收到来自初始查询的带有值的实体。这称为身份映射模式。您可以强制对象上下文重新加载实体,但是它将重新加载单个共享实例。
在调用SaveChanges
上下文之前,对实体所做的任何更改都不会保留。您可以在多个实体中进行更改并立即存储它们。这称为工作单元模式。您无法有选择地说出您要保存的修改后的附加实体。
结合这两种模式,您将看到一些有趣的效果。整个应用程序只有一个实体实例。对实体的任何更改都会影响整个应用程序,即使更改尚未持久(提交)。在大多数情况下,这不是您想要的。假设您在WPF应用程序中有一个编辑表单。您正在使用该实体,并决定取消复杂的编辑(更改值,添加相关实体,删除其他相关实体等)。但是该实体已经在共享上下文中被修改。你会怎么做?提示:我不知道关于的任何CancelChanges或UndoChanges ObjectContext
。
我认为我们不必讨论服务器方案。在多个HTTP请求或Web服务调用之间简单地共享单个实体会使您的应用程序无用。任何请求都只能触发SaveChanges
并保存来自另一个请求的部分数据,因为您要在所有请求之间共享一个工作单元。这也将带来另一个问题-上下文,并且对上下文中的实体或上下文使用的数据库连接进行的任何操作都不是线程安全的。
即使对于只读应用程序,全局上下文也不是一个好选择,因为每次查询应用程序时您可能都希望有新数据。
TransactionScope
不属于工作单元,而是属于您的业务逻辑,因为逻辑本身定义了事务。工作单元仅定义应一起保留的内容,而事务范围允许您在同一事务中多次使用工作单元持久性。
根据丹尼尔·西蒙斯的说法:
在Using语句中为每个服务方法创建一个新的ObjectContext实例,以便在方法返回之前将其丢弃。此步骤对于服务的可伸缩性至关重要。它可以确保数据库连接不会在服务调用之间保持打开状态,并且确保特定操作使用的临时状态在该操作结束时不会被垃圾回收。实体框架自动在应用程序域中缓存元数据和其他所需的信息,而ADO.NET则池化数据库连接,因此每次重新创建上下文都是一项快速的操作。
这来自他的综合文章:
http://msdn.microsoft.com/zh-CN/magazine/ee335715.aspx
我相信此建议会扩展到HTTP请求,因此对于ASP.NET是有效的。有状态的胖客户端应用程序(例如WPF应用程序)可能是“共享”上下文的唯一情况。
IDisposable
我认为ObjectContext / DbContext工具,因此应该在最短的合理时间内打开。
根据EF6(也包括4,5)文档:https ://msdn.microsoft.com/zh-cn/data/hh949853#9
9.3每个请求的上下文
实体框架的上下文旨在用作短期实例,以提供最佳的性能体验。预计上下文将短暂存在并被丢弃,因此上下文已实现为非常轻量级,并在可能的情况下重新使用元数据。在Web场景中,请记住这一点,并且不要让上下文超出单个请求的持续时间,这一点很重要。同样,在非Web场景中,应根据您对实体框架中不同级别的缓存的了解来丢弃上下文。一般来说,应该避免在应用程序的整个生命周期中都具有上下文实例,以及每个线程的上下文和静态上下文。
下面的代码用新的数据库值帮助刷新了我的对象。Entry(object).Reload()命令强制对象重新调用数据库值
GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();
CType(myContext, IObjectContextAdapter).ObjectContext.Refresh(RefreshMode.StoreWins,myCustomers)