很抱歉长标题:)
我真的找不到任何答案,这个问题已经在我脑海中盘旋了一段时间了。最后提问的简短摘要。
基本上我想知道linq to entity / sql在将结果集映射到其中一个实体/ sql类之前是否通过datareader循环,或者它是否已映射。在我可以遍历Iqueryable之前,Iqueryable是否必须遍历数据读取器。为了表明我在代码中的意思,我想知道是否
foreach(object o in SomeIQueryableObject)
{
...do stuff with the object
}
将导致A:
while(Reader.Read())
{
SomeIqueryableObject.Add(Reader.TranslateRow());
}
//now the iqueryable has been loaded with objects and we can loop through it
//with the above code
foreach(object o in SomeIQueryableObject)
{
...do stuff with the object
}
或者会导致B:
while(Reader.Read())
{
...do stuff with the object
}
//Iqueryable doesn't have to loop through Reader
//before you can loop through Iqueryable.
简短摘要:当我在一个iqueryable上使用foreach时,这相当于使用Reader.Read()
循环一个datareader答案 0 :(得分:2)
AFAIK EF将使用您的第二个选项。我这样说的原因是我经历过,当你在循环第一个查询的结果时执行另一个查询时,EF会打开第二个连接。由于我使用了一个事务,并且我禁用了分布式事务,并且第二个打开的连接(当第一个连接仍然打开并被使用时)禁用了当前事务的重用,我的第二个查询引发了一个异常,说DTC不是没有启用。
所以我的结论是:如果您正在执行查询并循环遍历结果(因此没有.ToList()
),那么查询仍在执行,并且连接仍然是打开的,并且如果EF正在使用数据-reader,然后是,它在从数据读取器读取的循环内。
答案 1 :(得分:2)
我担心这里的正确答案是:它取决于。
首先 - 它取决于我们所讨论的IQueryable
实施的类型; IQueryable<T>
只是一个接口,实际的实现留给了实现者。据我所知,微软没有就如何做到这一点提供任何严格的指导(哎呀,没有人说IQueryable<T>
需要与数据库有任何共同之处,这会使问题毫无意义。)
当我们将自己限制在linq-to-sql / entity-framework时,答案仍然是:它取决于(至少对于linq-to-sql,尽管如果EF的工作方式有所不同,我会感到惊讶)。这取决于几个因素(例如,您正在执行的查询类型,数据量等)。基本上它与第二个伪代码的工作方式类似(即不一次加载所有数据),但优化可用于在块/缓冲区中检索数据,因此在某些情况下,数据库端的查询执行可能比你的枚举(虽然试图利用这种方式可能是......非平凡的)。
如果要模拟批量加载版本,请显式调用ToList()
/ ToArray()
(或使用任何其他可能导致读取所有数据的方法)。