entity framework和连接池
我最近开始在我的.NET 4.0应用程序中使用Entity Framework 4.0,并对与池有关的一些事情感到好奇。
-
我所知道的连接池是由ADO.NET数据提供者pipe理的,在我的情况下是MS SQL服务器。 这是否适用于实例化新的实体上下文(
ObjectContext
),即无参数的new MyDatabaseModelEntities()
? -
a)为应用程序创build一个全局实体上下文(即一个静态实例)或b)为每个给定的操作/方法创build和展示一个实体上下文,并使用一个
using
块。 -
任何其他build议,最佳做法或对于某些应该了解的情况的常见方法?
- 连接池的处理与其他任何ADO.NET应用程序一样。 实体连接仍然使用传统的连接string与传统的数据库连接。 我相信你可以closures连接string中的连接池,如果你不想使用它。 (阅读有关SQL Server连接池(ADO.NET)的更多信息)
- 永远不要使用全局上下文。 ObjectContext内部实现了几个模式,包括标识映射和工作单元。 使用全局上下文的影响因应用程序types而异。
- 对于Web应用程序,请求使用单个上下文。 对于Web服务,每次调用使用一个上下文。 在WinForms或WPF应用程序中,每个表单或每个演示者使用单个上下文。 可以有一些特殊的要求,不允许使用这种方法,但在大多数情况下,这是足够的。
如果您想知道WPF / WinForm应用程序的单个对象上下文有什么影响,请查阅本文 。 这是关于NHibernate的会议,但想法是一样的。
编辑:
在使用EF时,默认情况下,每个上下文只加载一次实体。 第一个查询创build实体实例并将其存储在内部。 后续任何需要具有相同键的实体的查询都将返回此存储的实例。 如果数据存储中的值发生更改,您仍然收到来自初始查询的值的实体。 这就是所谓的身份映射模式 。 您可以强制对象上下文重新加载实体,但会重新加载一个共享实例。
在对上下文调用SaveChanges
之前,对实体所做的任何更改都不会被SaveChanges
。 您可以在多个实体中进行更改并一次存储它们。 这被称为工作单元模式 。 你不能有select地说你想保存哪个修改的附加实体。
结合这两种模式,你会看到一些有趣的效果。 整个应用程序只有一个实体实例。 即使变更尚未持续(提交),实体的任何更改都会影响整个应用程序。 在大多数情况下,这不是你想要的。 假设你在WPF应用程序中有一个编辑表单。 您正在与实体合作,并决定取消复杂的修改(更改值,添加相关实体,删除其他相关实体等)。 但是实体已经在共享上下文中被修改了。 你会怎么做? 提示:我不知道ObjectContext
上的任何CancelChanges或UndoChanges。
我想我们不必讨论服务器场景。 简单地在多个HTTP请求或Web服务调用之间共享单个实体使您的应用程序无用。 任何请求都可以触发SaveChanges
并从另一个请求中保存部分数据,因为您正在共享单个工作单元。 这也会有另一个问题 – 上下文中的实体的上下文和任何操作,或上下文使用的数据库连接都不是线程安全的。
即使对于只读应用程序,全局上下文也不是一个好的select,因为每次查询应用程序时都可能需要新的数据。
据Daniel Simmons说:
在每个服务方法的Using语句中创build一个新的ObjectContext实例,以便在方法返回之前处理它。 这一步对于您的服务的可扩展性至关重要。 它确保数据库连接不会在服务调用中保持打开状态,并且特定操作使用的临时状态在操作结束时将被垃圾收集。 entity framework自动caching它在应用程序域中所需的元数据和其他信息,而ADO.NET则池化数据库连接,因此每次重新创build上下文都是快速操作。
这是他的综合性文章:
http://msdn.microsoft.com/en-us/magazine/ee335715.aspx
我相信这个build议扩展到HTTP请求,所以对ASP.NET有效。 有状态的胖客户端应用程序(如WPF应用程序)可能是“共享”上下文的唯一情况。
符合EF6(4.5也)文档: https ://msdn.microsoft.com/en-us/data/hh949853#9
9.3每个请求的上下文
entity framework的上下文是为了提供最佳的性能体验而被用作短期实例 。 预计上下文会被短暂地丢弃,因此已经被实现为非常轻量级的,并且尽可能地重新使用元数据。 在web场景中,记住这一点非常重要,并且不要超过单个请求的持续时间。 类似地,在非web场景中,根据您对entity framework中不同级别的caching的理解,上下文应该丢弃。 一般来说,应该避免在应用程序的整个生命周期中有一个上下文实例,以及每个线程和静态上下文的上下文。
下面的代码帮助我的对象刷新新的数据库值。 Entry(object).Reload()命令强制对象调用数据库值
GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName); DatabaseObjectContext.Entry(member).Reload();