.net 实体框架和连接池
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3653009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework and Connection Pooling
提问by Noldorin
I've recently started to use the Entity Framework 4.0 in my .NET 4.0 application and am curious about a few things relating to pooling.
我最近开始在我的 .NET 4.0 应用程序中使用实体框架 4.0,并且对与池相关的一些事情感到好奇。
Connection pooling as I know is managed by the ADO.NET data provider, in my case that of MS SQL server. Does this apply when you instantiate a new entities context (
ObjectContext), i.e. the parameterlessnew MyDatabaseModelEntities()?What are the advantages and disadvantages of a) creating a global entities context for the application (i.e. one static instance) or b) creating and exposing an entities context for each given operation/method, with a
usingblock.Any other recommendations, best practices, or common approaches for certain scenarios that I should know about?
据我所知,连接池由 ADO.NET 数据提供程序管理,在我的例子中是 MS SQL 服务器。当你实例化一个新的实体上下文(
ObjectContext)时,这是否适用,即无参数new MyDatabaseModelEntities()?a) 为应用程序创建全局实体上下文(即一个静态实例)或 b) 使用
using块为每个给定的操作/方法创建和公开实体上下文的优缺点是什么。我应该了解的针对某些场景的任何其他建议、最佳实践或常用方法?
回答by Ladislav Mrnka
- Connection pooling is handled as in any other ADO.NET application. Entity connection still uses traditional database connection with traditional connection string. I believe you can turn off connnection pooling in connection string if you don't want to use it. (read more about SQL Server Connection Pooling (ADO.NET))
- Never ever use global context. ObjectContext internally implements several patterns including Identity Map and Unit of Work. Impact of using global context is different per application type.
- For web applications use single context per request. For web services use single context per call. In WinForms or WPF application use single context per form or per presenter. There can be some special requirements which will not allow to use this approach but in most situation this is enough.
- 连接池的处理方式与在任何其他 ADO.NET 应用程序中一样。实体连接仍然使用传统的数据库连接和传统的连接字符串。我相信如果您不想使用它,您可以关闭连接字符串中的连接池。(阅读有关SQL Server 连接池 (ADO.NET) 的更多信息)
- 永远不要使用全局上下文。ObjectContext 在内部实现了多种模式,包括身份映射和工作单元。使用全局上下文的影响因应用程序类型而异。
- 对于 Web 应用程序,每个请求使用单个上下文。对于 Web 服务,每次调用使用单个上下文。在 WinForms 或 WPF 应用程序中,每个表单或每个演示者使用单个上下文。可能有一些特殊要求不允许使用这种方法,但在大多数情况下这已经足够了。
If you want to know what impact has single object context for WPF / WinForm application check this article. It is about NHibernate Session but the idea is same.
如果您想知道 WPF/WinForm 应用程序的单个对象上下文有什么影响,请查看这篇文章。它是关于 NHibernate Session 但想法是一样的。
Edit:
编辑:
When you use EF it by default loads each entity only once per context. The first query creates entity instace and stores it internally. Any subsequent query which requires entity with the same key returns this stored instance. If values in the data store changed you still receive the entity with values from the initial query. This is called Identity map pattern. You can force the object context to reload the entity but it will reload a single shared instance.
当您使用 EF 时,默认情况下,每个上下文仅加载每个实体一次。第一个查询创建实体实例并将其存储在内部。任何需要具有相同键的实体的后续查询都会返回此存储的实例。如果数据存储中的值发生更改,您仍会收到带有初始查询值的实体。这称为身份映射模式。您可以强制对象上下文重新加载实体,但它会重新加载单个共享实例。
Any changes made to the entity are not persisted until you call SaveChangeson the context. You can do changes in multiple entities and store them at once. This is called Unit of Work pattern. You can't selectively say which modified attached entity you want to save.
在您调用SaveChanges上下文之前,对实体所做的任何更改都不会持久化。您可以在多个实体中进行更改并一次存储它们。这称为工作单元模式。您不能有选择地说出要保存哪个修改后的附加实体。
Combine these two patterns and you will see some interesting effects. You have only one instance of entity for the whole application. Any changes to the entity affect the whole application even if changes are not yet persisted (commited). In the most times this is not what you want. Suppose that you have an edit form in WPF application. You are working with the entity and you decice to cancel complex editation (changing values, adding related entities, removing other related entities, etc.). But the entity is already modified in shared context. What will you do? Hint: I don't know about any CancelChanges or UndoChanges on ObjectContext.
结合这两种模式,你会看到一些有趣的效果。整个应用程序只有一个实体实例。即使更改尚未持久化(提交),对实体的任何更改也会影响整个应用程序。在大多数情况下,这不是您想要的。假设您在 WPF 应用程序中有一个编辑表单。您正在处理实体,并决定取消复杂的编辑(更改值、添加相关实体、删除其他相关实体等)。但是实体已经在共享上下文中被修改了。你会怎么做?提示:我不知道 上的任何 CancelChanges 或 UndoChanges ObjectContext。
I think we don't have to discuss server scenario. Simply sharing single entity among multiple HTTP requests or Web service calls makes your application useless. Any request can just trigger SaveChangesand save partial data from another request because you are sharing single unit of work among all of them. This will also have another problem - context and any manipulation with entities in the context or a database connection used by the context is not thread safe.
我认为我们不必讨论服务器场景。在多个 HTTP 请求或 Web 服务调用之间简单地共享单个实体会使您的应用程序无用。任何请求都可以触发SaveChanges并保存来自另一个请求的部分数据,因为您在所有请求之间共享单个工作单元。这还会有另一个问题 - 上下文和对上下文中的实体或上下文使用的数据库连接的任何操作都不是线程安全的。
Even for a readonly application a global context is not a good choice because you probably want fresh data each time you query the application.
即使对于只读应用程序,全局上下文也不是一个好的选择,因为每次查询应用程序时您可能都需要新数据。
回答by Dave Swersky
According to Daniel Simmons:
根据丹尼尔西蒙斯的说法:
Create a new ObjectContext instance in a Using statement for each service method so that it is disposed of before the method returns. This step is critical for scalability of your service. It makes sure that database connections are not kept open across service calls and that temporary state used by a particular operation is garbage collected when that operation is over. The Entity Framework automatically caches metadata and other information it needs in the app domain, and ADO.NET pools database connections, so re-creating the context each time is a quick operation.
在 Using 语句中为每个服务方法创建一个新的 ObjectContext 实例,以便在方法返回之前处理它。此步骤对于服务的可扩展性至关重要。它确保数据库连接不会在服务调用之间保持打开状态,并且特定操作使用的临时状态在该操作结束时被垃圾收集。实体框架在应用程序域中自动缓存元数据和它需要的其他信息,并且 ADO.NET 池化数据库连接,因此每次重新创建上下文是一个快速操作。
This is from his comprehensive article here:
这是他的综合文章在这里:
http://msdn.microsoft.com/en-us/magazine/ee335715.aspx
http://msdn.microsoft.com/en-us/magazine/ee335715.aspx
I believe this advice extends to HTTP requests, so would be valid for ASP.NET. A stateful, fat-client application such as a WPF application might be the only case for a "shared" context.
我相信这个建议扩展到 HTTP 请求,所以对 ASP.NET 有效。有状态的胖客户端应用程序(例如 WPF 应用程序)可能是“共享”上下文的唯一情况。
回答by Raj Rao
Accoriding to EF6 (4,5 also) documentation: https://msdn.microsoft.com/en-us/data/hh949853#9
根据 EF6(也为 4,5)文档:https://msdn.microsoft.com/en-us/data/hh949853#9
9.3 Context per request
9.3 每个请求的上下文
Entity Framework's contexts are meant to be used as short-lived instances in order to provide the most optimal performance experience. Contexts are expected to be short lived and discarded, and as such have been implemented to be very lightweight and reutilize metadata whenever possible. In web scenarios it's important to keep this in mind and not have a context for more than the duration of a single request. Similarly, in non-web scenarios, context should be discarded based on your understanding of the different levels of caching in the Entity Framework. Generally speaking, one should avoid having a context instance throughout the life of the application, as well as contexts per thread and static contexts.
实体框架的上下文旨在用作短期实例,以提供最佳性能体验。上下文预计是短暂的并被丢弃,因此已被实现为非常轻量级并尽可能重用元数据。在 Web 场景中,记住这一点很重要,并且上下文不能超过单个请求的持续时间。同样,在非 Web 场景中,根据您对实体框架中不同级别缓存的理解,应该丢弃上下文。一般来说,应该避免在应用程序的整个生命周期中拥有上下文实例,以及每个线程和静态上下文的上下文。
回答by HGMamaci
Below code helped my object to be refreshed with fresh database values. The Entry(object).Reload() command forces the object to recall database values
下面的代码帮助我的对象用新的数据库值刷新。Entry(object).Reload() 命令强制对象调用数据库值
GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();

