ChatGPT解决这个技术问题 Extra ChatGPT

我最近开始在我的 .NET 4.0 应用程序中使用 Entity Framework 4.0,并对与池相关的一些事情感到好奇。

据我所知,连接池由 ADO.NET 数据提供程序管理,在我的例子中是 MS SQL 服务器。这在您实例化一个新的实体上下文 (ObjectContext) 时是否适用,即无参数的 new MyDatabaseModelEntities()? a) 为应用程序创建全局实体上下文(即一个静态实例)或 b) 使用 using 块为每个给定操作/方法创建和公开实体上下文的优点和缺点是什么。对于某些场景,我应该了解的任何其他建议、最佳实践或常用方法?


e
ebram khalil

连接池的处理方式与任何其他 ADO.NET 应用程序一样。实体连接仍然使用传统的数据库连接和传统的连接字符串。我相信如果您不想使用它,可以关闭连接字符串中的连接池。 (阅读有关 SQL Server 连接池 (ADO.NET) 的更多信息)永远不要使用全局上下文。 ObjectContext 在内部实现了几种模式,包括身份映射和工作单元。使用全局上下文的影响因应用程序类型而异。对于 Web 应用程序,每个请求使用单个上下文。对于 Web 服务,每次调用使用单个上下文。在 WinForms 或 WPF 应用程序中,每个表单或每个演示者使用单个上下文。可能有一些特殊要求不允许使用这种方法,但在大多数情况下这已经足够了。

如果您想知道 WPF/WinForm 应用程序的单个对象上下文有什么影响,请查看此 article。这是关于 NHibernate Session 但想法是一样的。

编辑:

当您使用 EF 时,默认情况下每个上下文仅加载每个实体一次。第一个查询创建实体实例并将其存储在内部。任何需要具有相同键的实体的后续查询都会返回此存储的实例。如果数据存储中的值发生更改,您仍会收到带有初始查询值的实体。这称为身份映射模式。您可以强制对象上下文重新加载实体,但它会重新加载单个共享实例。

在您对上下文调用 SaveChanges 之前,不会保留对实体所做的任何更改。您可以对多个实体进行更改并一次存储它们。这称为工作单元模式。您不能有选择地说出要保存哪个修改后的附加实体。

结合这两种模式,你会看到一些有趣的效果。整个应用程序只有一个实体实例。即使更改尚未持久化(提交),对实体的任何更改也会影响整个应用程序。在大多数情况下,这不是您想要的。假设您在 WPF 应用程序中有一个编辑表单。您正在使用实体并决定取消复杂的编辑(更改值、添加相关实体、删除其他相关实体等)。但是实体已经在共享上下文中进行了修改。你会怎么做?提示:我不知道 ObjectContext 上有任何 CancelChanges 或 UndoChanges。

我认为我们不必讨论服务器场景。简单地在多个 HTTP 请求或 Web 服务调用之间共享单个实体会使您的应用程序毫无用处。任何请求都可以触发 SaveChanges 并保存来自另一个请求的部分数据,因为您在所有请求之间共享单个工作单元。这也会带来另一个问题——上下文以及对上下文中实体的任何操作或上下文使用的数据库连接都不是线程安全的。

即使对于只读应用程序,全局上下文也不是一个好的选择,因为您可能每次查询应用程序时都需要新数据。


感谢您的回复。也许您可以详细说明为什么使用单个全局上下文是不好的?当然,它使并行访问更加困难,但是还有什么……?
好的,现在清楚多了,谢谢。只是为了确认,尽管全局上下文从来都不是真正合适的,但“编辑对话框”的单个上下文或类似的可能是正确的方式?在其他情况下,例如 Web 服务和 ASP.NET,方法中的上下文只会更有意义。关于正确?
我接受了你的建议并删除了单曲。现在我收到另一个错误:stackoverflow.com/questions/14795899/…
@RudolfDvoracek:很容易。 TransactionScope 不属于工作单元,它属于您的业务逻辑,因为逻辑本身定义了事务。工作单元仅定义应该一起持久化的内容,而事务范围允许您在同一事务中多次使用工作单元持久性。
@MaxToro:如果您不与不属于同一工作单元的操作共享它们,则可以使用任意数量的上下文。通过使用更多上下文,您可以解决跟踪实体的一些问题。
D
Dave Swersky

根据丹尼尔西蒙斯的说法:

在 Using 语句中为每个服务方法创建一个新的 ObjectContext 实例,以便在方法返回之前将其处理掉。此步骤对于您的服务的可扩展性至关重要。它确保数据库连接不会在服务调用之间保持打开状态,并且特定操作使用的临时状态在该操作结束时被垃圾收集。 Entity Framework 会自动在应用程序域中缓存元数据和它需要的其他信息,并且 ADO.NET 将数据库连接池化,因此每次重新创建上下文是一个快速操作。

这是来自他的综合文章:

http://msdn.microsoft.com/en-us/magazine/ee335715.aspx

我相信这个建议可以扩展到 HTTP 请求,因此对 ASP.NET 也是有效的。有状态的胖客户端应用程序(例如 WPF 应用程序)可能是“共享”上下文的唯一情况。


谢谢,这是一个非常有用的报价。但是,我仍然想知道共享(全局)上下文是否适用于客户端 WPF 应用程序等。即使在这种情况下有什么优势吗?
WPF 应用程序中的全局上下文不会有任何优势,但也可能不会有重大损害。如果您确实实现了全局上下文,则在高请求率的情况下,您可能必须手动管理数据库连接(显式关闭连接)。
正确的;所以基本上我永远不会通过使用多个临时上下文而真正出错(假设我知道正在发生连接池)? ...如果您使用单个全局上下文,理论上连接不会在随机时间点下降吗?
@Nolodrin:我不认为连接会“随机”断开......风险是连接可能会保持打开时间过长并使连接池饱和。
ObjectContext/ DbContext 实现IDisposable,因此应该在最短的合理时间内打开,这是我的看法。
R
Raj Rao

根据 EF6(也有 4,5)文档:https://msdn.microsoft.com/en-us/data/hh949853#9

9.3 每个请求的上下文

实体框架的上下文旨在用作短期实例,以提供最佳性能体验。上下文预计将是短暂的并被丢弃,因此已实现非常轻量级并尽可能重用元数据。在 Web 场景中,记住这一点很重要,并且上下文的持续时间不会超过单个请求的持续时间。同样,在非 Web 场景中,应根据您对实体框架中不同级别缓存的理解丢弃上下文。一般来说,应该避免在应用程序的整个生命周期中使用上下文实例,以及每个线程的上下文和静态上下文。


我知道这个回复已经有一段时间了,但我不得不说这让我很头疼。将 EF 与 Oracle 一起使用时不断出现“池化连接”错误,并且无法弄清楚原因。我已将 dbContext 设置为类变量,并在创建时对其进行实例化。将其更改为根据需要创建上下文解决了我的世界的所有弊病。谢谢!
你能解释一下为什么上下文应该只作用域和单例/瞬态实例吗?那么会出现什么样的错误呢?
如果不使用 EF 池,那么这是否意味着 sql 不会池连接?
H
HGMamaci

下面的代码帮助我的对象用新的数据库值刷新。 Entry(object).Reload() 命令强制对象调用数据库值

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)