假设我有一些使用伪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
关闭连接?在那种情况下它会被关闭吗?将关闭什么连接 - 使用语句或lambda表达式中的连接? .NET编译器正在为lambdas创建匿名类,因此它将复制到该类的连接。什么时候关闭?
不知何故,我成功地获得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.
物化查询,异常消失了。但是我想知道这件事是如何起作用的。
答案 0 :(得分:4)
这完全取决于您的ORM。如果处置ConnectionFactory.Current.GetDBConnection()
关闭连接,那么您将永远无法枚举结果。如果它没有关闭连接(以及其他东西),它可能会起作用,具体取决于其他人是否已关闭连接。
在任何情况下,你可能都不希望从创建和处理连接的东西返回一个未枚举的枚举。
在关闭之前枚举集合,例如:
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();
}
}
答案 1 :(得分:0)
: 在此调用连接中使用范围打开,在usnig范围结束时没有任何提取数据已关闭。
var aItems = GetA();
但是在这一行:
if (!aItems.Any())
没有任何开放连接
答案 2 :(得分:0)
关闭连接对象时,Linq2db释放连接。在您的示例中,它发生在您离开using
块并且处置db
对象时。这意味着您不能从连接范围返回查询-您需要先获取数据或推迟连接处理,直到没有获得所有必需的数据为止。
您观察到的异常是由于1.8.0之前的linq2db中的错误所致,该错误允许在已处置的连接上执行查询,从而导致连接泄漏。有关更多详细信息,请参见https://github.com/linq2db/linq2db/issues/445。完成此修复后,您将无法在示例中编写类似于GetA()
的代码,因为尝试枚举结果时将得到ObjectDisposedException
。