如果使用 IEnumerable,何时关闭连接

When will connection be closed in case of IEnumerable with using

假设我有使用一些伪 ORM 的伪代码(在我的例子中是 Linq2Db)。

static IEnumerable<A> GetA()
{
  using (var db = ConnectionFactory.Current.GetDBConnection())
  {
     return from a in db.A
            select a;
  }
}
static B[] DoSmth()
{
  var aItems = GetA();
  if (!aItems.Any())
    return null;
  return aItems.Select(a => new B(a.prop1)).ToArray();
}

db什么时候关闭连接?在那种情况下它会完全关闭吗?将关闭什么连接 - 那些在 using 语句中的还是那些在 lambda 表达式中的? .NET 编译器正在为 lambda 创建匿名 class,因此它会将连接复制到那个 class。该连接何时关闭?

我以某种方式设法得到 Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. 我具体化了查询并且异常消失了。但是我想知道这个东西是如何工作的。

第一次通话后: 在此调用连接中使用范围打开,在 usnig 范围结束时未获取任何数据 Closed.

var aItems = GetA();

但在这一行:

if (!aItems.Any())

没有任何打开的连接

这完全取决于您的 ORM。如果处理 ConnectionFactory.Current.GetDBConnection() 关闭连接,那么您将永远无法枚举结果。如果它没有关闭连接(而其他东西关闭了),它可能会起作用,这取决于其他人是否关闭了连接。

在任何情况下,您可能都不希望 return 从创建和处理连接的事物中获取未枚举的可枚举。

要么在关闭之前枚举集合,例如:

static IEnumerable<A> GetA()
{
  using (var db = ConnectionFactory.Current.GetDBConnection())
  {
     return (from a in db.A
            select a).ToArray();
  }
}

或在枚举结果的级别控制连接,例如:

static IEnumerable<A> GetA(whatevertype db)
{
   return from a in db.A
          select a;
}
static B[] DoSmth()
{
  using (var db = ConnectionFactory.Current.GetDBConnection())
  {
    var aItems = GetA(db);
    if (!aItems.Any())
      return null;
    return aItems.Select(a => new B(a.prop1)).ToArray();
  }
}

Linq2db 在您关闭连接对象时释放连接。在您的示例中,当您离开 using 块并处理 db 对象时,就会发生这种情况。这意味着您不能 return 从连接范围查询 - 您需要先获取数据或推迟连接处理,直到您没有获得所有必需的数据。

您观察到的异常是由于 1.8.0 之前的 linq2db 中的错误,它允许在已处理的连接上执行查询,这会导致连接泄漏。有关详细信息,请参阅 https://github.com/linq2db/linq2db/issues/445。在该修复之后,您将无法在示例中编写类似 GetA() 的代码,因为当您尝试枚举结果时,您将获得 ObjectDisposedException