【问题标题】:Do I need to force a Dispose after a LINQ query?我需要在 LINQ 查询后强制 Dispose 吗?
【发布时间】:2015-02-19 03:39:54
【问题描述】:

我的 DBA 说打开的连接太多,他认为是我在 .net 中的代码使它们保持打开状态。

我首先使用 LINQ 查询和 EF 代码。

示例方法:

 public List<Stuff> GetStuff()
 {
      var db = new DBContext();

      var results =  db.stuff.toList();

      return results;
 }

完成后是否需要处理 db var?我的理解是我不需要在 EF 和 LINQ 中。请向我指出有关在代码中管理连接或 LINQ/EF 和数据库连接的最佳实践的 Microsoft 文档

更新:

我加了

db.Connection.Close();
db.Dispose();

执行完这两行后,我仍然在 SQL 中看到打开的连接。强制关闭时它不会关闭的原因是什么?

【问题讨论】:

  • 如果是IDisposable,最好将其包装在using 语句中。
  • 我回到我的所有代码并将其包装在 using 语句中。然后我意识到我在做延迟加载。这不适用于延迟加载。所以我回去并恢复了所有代码并依靠 DataContext 来管理连接

标签: c# entity-framework database-connection idisposable


【解决方案1】:

您应该听取您的 DBA 的意见!是的,使用using。不要让连接不必要地打开。您应该连接,与数据库做生意,然后关闭该连接,将其释放给另一个进程。在大容量系统中尤其如此。

编辑。让我在这里用我自己的经历进一步解释一下。在小批量处理中,这可能不是问题,但当它明确实现 IDisposable 时,不明确处理或不将其包装在 using 中是一个坏习惯。

在高容量的情况下,这只是要求灾难。 Sql server 将为每个应用程序分配如此多的连接(可以在连接字符串中指定)。如果没有及时关闭,进程将花费时间等待连接释放。在某些情况下,这通常会导致超时或死锁。

当然,您可以调整 Sql 服务器连接管理等,但每次调整设置时,您都会做出妥协。您必须考虑运行备份、运行其他作业等。这就是为什么聪明的开发人员会听取他们的 DBA 警告的原因。这并不总是与代码有关......

【讨论】:

  • 我添加了 db.Connection.Close() 和 db.Dispose() 但连接在 SQL 中保持打开状态??我知道没有其他对数据库的调用,就像第一行代码一样,我是唯一连接到数据库的用户。
  • 没有投反对票。也没有投票,因为这完全忽略了这样一个事实,即默认情况下,EF 已经在每次单独的数据库交互后关闭连接。您可以在没有任何打开连接的情况下让上下文存活数小时(尽管这不明智)。所以 如果 DbContext 被使用,除了“将连接管理留给 DbContext”之外别无选择。
  • 这个 EF6 及更高版本的 msdn 帖子似乎表明连接确实保持打开状态,直到调用 Dispose()...msdn.microsoft.com/en-us/data/dn456849.aspx(在文章末尾,查看它在哪里谈论 EF6 和稍后)
  • 这是关于提供到上下文的开放连接或从调用代码打开连接。在这种情况下,EF 将永远不会关闭它(当接收到连接时)或在上下文处置时(当通过调用代码打开时)。这是为了支持场景,例如EF 和遗留代码应该在一个事务中运行。因此,只有在开发人员明确选择这样做时才会发生。因此,虽然using 是一种很好的做法,但在标准情况下,在使用 EF 时关闭连接是不必要的。
  • @didaxi,我想做的第一件事就是返回并关闭连接并将其包裹在 using 中。但后来它打破了我的一些观点,因为在视图中它需要延迟加载,并且如果上下文已被释放,则它无法重新连接以获取子数据。所以在我听我的 DBA 或继续使用 YES 之前,请使用 using。我们需要更多信息来了解该应用程序是如何开发的以及使用了哪些技术。旧的 ado.net 我们将以编程方式关闭连接,但使用新的 EF 数据上下文,我们依赖并相信它将为我们处理它。
【解决方案2】:

我刚刚问过这个same question over on Programmers.SE。罗伯特哈维给出了一个很好的答案。

通常,您不需要将 Using 语句与实体框架数据上下文一起使用。懒惰的收藏是原因之一。

我鼓励您阅读 Programmers.SE 上的完整答案以及 Robert 在答案中提供的链接。

【讨论】:

  • OP 正在使用 .toList()
【解决方案3】:

据我所知,实体框架默认使用connection pooling 来减少每次创建新连接的开销。 关闭应用程序时连接是否关闭?

如果是这样,您可以尝试减少连接字符串中的最大池大小或完全禁用连接池。 请参阅 here 以获取连接字符串中可能选项的参考。

【讨论】:

    【解决方案4】:

    默认情况下,DbContext 会自动为您管理连接。因此,您不必显式调用 Dispose。

    关于该主题的博文:Link

    但我相信,如果您要处理大量请求,则不进行处置可能会导致性能问题。您应该添加一条 using 语句,以查看它是否会导致您的情况出现问题。

    【讨论】:

      【解决方案5】:

      是的,如果您的方法定义了工作单元;不,如果是更原始的东西。 (P.S. 你的代码中的某处应该定义一个工作单元,并且那个东西应该被包裹在一个 using (var context = new DbContext()) {} 或同等的东西中。)

      如果你属于那种认为你的DbContext 你的工作单元的思想流派,那么你将总是用using 块包裹那个坏男孩:本地缓存先前在上下文生命周期中获取的数据与SaveChanges 方法一起充当一种轻量级事务,并且您的Dispose(不调用SaveChanges)是您的回滚(而您的SaveChanges 是您的提交)。

      【讨论】:

        【解决方案6】:

        看看这个,这是一个关于如何使用 IDisposable 对象的标准协议。 https://msdn.microsoft.com/en-us/library/yh598w02.aspx

        上面写着:

        “通常,当您使用 IDisposable 对象时,您应该在 using 语句中声明和实例化它。”

        由于他们可以访问非托管资源,因此您应该始终考虑使用“使用”语句。

        【讨论】:

          猜你喜欢
          • 2019-03-10
          • 2010-10-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-31
          相关资源
          最近更新 更多