我最近开始在.NET 4.0应用程序中使用Entity Framework 4.0,并对与池化相关的一些事情感到好奇。
据我所知,连接池由ADO.NET数据提供程序管理,在我的情况下是MS SQL服务器。当您实例化新的实体上下文(ObjectContext
)时,这是否适用,即无参数new MyDatabaseModelEntities()
?
a)为应用程序创建全局实体上下文(即一个静态实例)或b)为每个给定操作/方法创建和公开实体上下文的优点和缺点是什么,{{1阻止。
我应该了解的某些方案的任何其他建议,最佳做法或常用方法?
答案 0 :(得分:360)
如果您想知道WPF / WinForm应用程序的单个对象上下文有什么影响,请检查此article。这是关于NHibernate Session,但想法是一样的。
修改强>
当您使用EF时,默认情况下,每个上下文仅加载一个实体。第一个查询创建实体实例并在内部存储它。任何需要具有相同键的实体的后续查询都会返回此存储的实例。如果数据存储中的值发生更改,您仍会收到包含初始查询值的实体。这称为身份映射模式。您可以强制对象上下文重新加载实体,但它将重新加载单个共享实例。
在您对上下文调用SaveChanges
之前,不会保留对该实体所做的任何更改。您可以在多个实体中进行更改并立即存储它们。这称为工作单元模式。您无法有选择地说出要保存的修改后的附加实体。
结合这两种模式,你会看到一些有趣的效果。整个应用程序只有一个实体实例。即使尚未保留(提交)更改,对实体的任何更改都会影响整个应用程序。在大多数情况下,这不是你想要的。假设您在WPF应用程序中有一个编辑表单。您正在与实体合作,并决定取消复杂的编辑(更改值,添加相关实体,删除其他相关实体等)。但该实体已在共享上下文中进行了修改。你会怎么做?提示:我不知道ObjectContext
上的任何CancelChanges或UndoChanges。
我认为我们不必讨论服务器方案。简单地在多个HTTP请求或Web服务调用之间共享单个实体会使您的应用程序无用。任何请求都可以触发SaveChanges
并保存来自其他请求的部分数据,因为您在所有请求之间共享单个工作单元。这还有另一个问题 - 上下文和上下文中的实体或上下文使用的数据库连接的任何操作都不是线程安全的。
即使对于只读应用程序,全局上下文也不是一个好选择,因为每次查询应用程序时都可能需要新数据。
答案 1 :(得分:64)
Daniel Simmons说:
在中创建一个新的ObjectContext实例 每个服务的using语句 处理它的方法 在方法返回之前。 此步骤对于服务的可伸缩性至关重要。它确保数据库连接不会在服务调用之间保持打开状态,并且当该操作结束时,特定操作使用的临时状态将被垃圾收集。实体框架自动在应用程序域中缓存它所需的元数据和其他信息,并且ADO.NET汇集数据库连接,因此每次重新创建上下文都是一种快速操作。
这是他在这里的综合文章:
http://msdn.microsoft.com/en-us/magazine/ee335715.aspx
我相信这个建议扩展到HTTP请求,因此对ASP.NET有效。有状态的胖客户端应用程序(如WPF应用程序)可能是“共享”上下文的唯一情况。
答案 2 :(得分:10)
符合EF6(4,5也)文件: https://msdn.microsoft.com/en-us/data/hh949853#9
9.3每个请求的上下文
实体框架的上下文旨在用作短期实例,以提供最佳的性能体验。预期上下文将是短暂的并且被丢弃,因此已经实现了非常轻量级并且尽可能地重新使用元数据。在Web方案中,重要的是要记住这一点,并且不要有超过单个请求持续时间的上下文。同样,在非Web方案中,应根据您对实体框架中不同级别的缓存的理解来丢弃上下文。 一般来说,应避免在应用程序的整个生命周期中使用上下文实例,以及每个线程和静态上下文的上下文。
答案 3 :(得分:1)
下面的代码帮助我的对象刷新了新的数据库值。 Entry(object).Reload()命令强制对象调用数据库值
GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();