我最近开始在我的.NET 4.0应用程序中使用EntityFramework4.0,并且对一些与池相关的事情感到好奇。
据我所知,连接池是由ADO.NET数据提供程序管理的,在我的情况下是由MS SQL Server管理的。当您实例化一个新的实体上下文(ObjectContext时,即无参数的new MyDatabaseModelEntities()时,这是否适用?
a)为应用程序创建全局实体上下文(即一个静态实例)或b)为每个给定的操作/方法创建和公开实体上下文(使用using块),其优点和缺点是什么?
对于我应该了解的某些场景,还有其他建议、最佳实践或常见方法吗?
连接池的处理方式与任何其他ADO.NET应用程序相同。实体连接仍然使用传统的数据库连接和传统的连接字符串。我相信如果不想使用连接字符串中的连接池,您可以关闭它。(阅读有关SQL Server连接池(ADO.NET)的详细信息)
永远不要使用全局上下文。ObjectContext在内部实现了几个模式,包括标识映射和工作单元。使用全局上下文对每个应用程序类型的影响是不同的。
对于Web应用程序,每个请求使用单个上下文。对于Web服务,每次调用使用单个上下文。在WinForms或WPF应用程序中,每个窗体或每个演示者使用单个上下文。可能有一些特殊的要求不允许使用这种方法,但在大多数情况下,这已经足够了。
如果您想知道对WPF/WinForm应用程序的单个对象上下文有什么影响,请检查本文。这是关于NHibernate会议,但想法是一样的。
编辑:
使用ef时,默认情况下,每个上下文只加载一次每个实体。第一个查询创建实体实例并将其存储在内部。任何需要具有相同键的实体的后续查询都会返回此存储实例。如果数据存储区中的值发生更改,您仍然可以从初始查询接收包含值的实体。这被称为身份映射模式。可以强制对象上下文重新加载实体,但它将重新加载单个共享实例。
在上下文中调用SaveChanges之前,对实体所做的任何更改都不会持久。您可以在多个实体中进行更改并同时存储它们。这被称为工作单元模式。不能有选择地说出要保存的修改后的附加实体。
结合这两种模式,您将看到一些有趣的效果。整个应用程序只有一个实体实例。对实体的任何更改都会影响整个应用程序,即使更改尚未持久化(提交)。在大多数情况下,这不是你想要的。假设您在WPF应用程序中有一个编辑表单。您正在处理该实体,并决定取消复杂的编辑(更改值、添加相关实体、删除其他相关实体等)。但是该实体已经在共享上下文中进行了修改。你会怎么做?提示:我不知道ObjectContext上有任何取消更改或撤消更改。
我想我们不必讨论服务器场景。只需在多个HTTP请求或Web服务调用之间共享单个实体,应用程序就没用了。任何请求都可以触发SaveChanges并保存来自另一个请求的部分数据,因为您在所有请求中共享单个工作单元。这也会有另一个问题——上下文和上下文中的实体或上下文使用的数据库连接的任何操作都不是线程安全的。
即使对于只读应用程序,全局上下文也不是一个好的选择,因为您可能希望每次查询应用程序时都有新的数据。
- 谢谢你的回复。也许你可以详细说明为什么使用单一的全球环境是不好的?当然,这使得并行访问更加困难,但是还有什么……?
- 好吧,现在说得更清楚了,谢谢。只是为了确认,尽管全局上下文从来不是真正合适的,"编辑对话框"或类似的单个上下文可能是正确的方式?在其他情况下,如Web服务和ASP.NET,方法中的上下文只会更有意义。关于正确吗?
- 我接受了你的建议,把歌手搬走了。现在我得到了另一个错误:stackoverflow.com/questions/14795899/…
- 我理解工作模式的实现单元和封装的dbContext应该将业务逻辑和数据库操作分开。我无法理解如何实现工作单元模式,并且仅对某些操作使用TransactionScope。
- @鲁道夫:很容易。TransactionScope不属于工作单元,它属于您的业务逻辑,因为逻辑本身定义了事务。工作单元只定义应该一起持久化的内容,而事务范围允许您在同一事务中多次使用工作单元持久化。
- 每个请求模式的上下文如何与连接池相关?池的整体思想是,您可以创建任意多的上下文,它们将使用可用的连接。
- @maxtoro:如果不与不属于同一工作单元的操作共享上下文,那么可以使用任意多的上下文。通过使用更多的上下文,您可以在跟踪实体时遇到一些问题。
- 在Web服务的上下文中,静态变量不是只有工作级别的作用域吗?当一个工作进程被丢弃时,它的静态引用就消失了,对吗?一个给定的工人不是单线程的吗?给定的工作进程一次只处理一个请求,对吗?所以,您不应该让请求使用相同的对象上下文并行处理,并相互踩踏?但我想,如果在处理一个请求时故意不保存更改,那么下一个请求的处理可能会无意中保存它们。这种事情肯定会发生。
- 我认为,这种可能性实际上是像ef框架这样的表单创建者通常主张最小化对象上下文的范围和生存期的主要原因,因为在处理给定事务之后,给定上下文的结束状态可能不会使另一个事务可以立即进行。上下文可能处于错误状态或未保存状态、呈现结果的状态等。可能性足够复杂,因此经验往往使人清楚尝试重用它们。
- @沙维斯:你的意思是在IIS中的工作进程吗?这不是单线程的。
- @拉迪斯拉夫:对,我知道你是对的。因此,如果静态具有工作区作用域(而不是工作线程作用域),并且应用程序域有一定数量的工作区,工作区有一定数量的线程。静态的确切范围是什么?它不是应用程序域范围,也不是请求范围,介于两者之间。
- @shavais:web进程可以承载多个appdomain(每个appdomain表示单独的web应用程序)。每个AppDomain都有自己的线程池,其中包含为传入请求提供服务的线程。静态变量具有AppDomain作用域。拥有多个Web进程托管同一个应用程序仍然意味着每个AppDomain都有自己的静态变量。这就是为什么ASP.NET中的进程内会话对于Web花园和Web场不起作用的原因。
根据丹尼尔·西蒙斯的说法:
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.
这是他的综合文章:
http://msdn.microsoft.com/en-us/magazine/ee335715.aspx
我相信这个建议扩展到了HTTP请求,所以对于ASP.NET是有效的。一个有状态的胖客户端应用程序(如WPF应用程序)可能是"共享"上下文的唯一情况。
- 谢谢,这是一个非常有用的引语。但是,我仍然想知道,即使对于客户端WPF应用程序,共享(全局)上下文是否合适。在这种情况下有什么好处吗?
- WPF应用程序中的全球环境没有优势,但也可能没有重大损害。如果确实实现了全局上下文,那么在请求率高的情况下,可能需要手动管理数据库连接(显式关闭连接)。
- 是的;所以本质上我永远不会因为使用多个临时上下文而出错(假设我知道正在发生连接池)?…如果你使用的是单一的全局上下文,那么理论上的联系是否会在某个时间点上消失呢?
- @诺洛德林:我不认为连接会"随机"中断……风险在于,连接可能被打开太长时间,并使连接池饱和。
- 当然,如果SQL服务器甚至传输线突然中断的话,他们也可以。互联网是一个几乎没有绝对保证的地方。;-)
- ObjectContext/dbContext实现IDisposable,因此应该在最短的合理时间内打开,这是我的观点。
根据该文件ef6(4.5 also to):msdn.microsoft.com HTTPS:/ / / / / hh949853销售额# 9日P></
9.3 context为requestP></
S是framework' entity to be used as的意思是语境中的短lived阶情况下提供最最优性能的经验。语境are expected to be short lived和have been discarded without这样,当要实现再利用元数据和lightweight to be possible甚当。在Web是important to keep this场景在心灵和not have a context for the duration of a超过单个请求。similarly,非Web context should be discarded without场景,基于不同层次的理解of the of the entity的缓存框架。generally说,在一审有avoid should the context of the application的整个生命,对As和As线程静态语境是语境。P></
- 我知道这个答复在这里已经有一段时间了,但我不得不说这让我省去了很多头痛。在Oracle中使用ef时,不断出现"池连接"错误,无法找出原因。我已经将dbContext设置为类变量,并在创建时实例化它。把它改为根据需要创造环境,解决了我这个世界的所有问题。谢谢您!
下面的代码帮助我的对象使用新的数据库值进行刷新。entry(object).reload()命令强制对象调用数据库值
1 2
| GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload(); |
- 以及这个集合(vb代码):CType(myContext, IObjectContextAdapter).ObjectContext.Refresh(RefreshMode.StoreWins,myCustomers)。