2016-06-10 36 views
1

我一直在看一个当然笔者提到这里,如果你有一些IQueryable的,说:迭代的IQueryable用foreach与调用ToList(),然后做的forEach - 性能

var someQuery = dbContext.Table.Where(x => x.Name == "Mark"); 

,然后尝试使用forEach迭代someQuery的结果,它会保持数据库连接处于打开状态,直到整个forEach结束,并且很多初学者开发者犯了这个错误,并且在forEach中执行了大量逻辑。相反,她建议只在前台调用toList(),然后在内存中收集forEach

虽然我找不到任何参考,但实体框架会保持数据库处于打开状态,直到forEach循环停止。我如何评估这是否真正的性能?

+0

我已经[发现了困难的方式](http://stackoverflow.com/a/22530381/261050) – Maarten

+0

是的,它会保持连接打开,直到它遇到.toL​​ist() –

+1

连接保持打开,直到枚举'IQueryable'完成。这会发生在'foreach'循环结尾或调用'.ToList()'时。然而,不清楚的是,以这种或那种方式进行这种表演会有性能损失。确保数据库连接长时间保持打开状态肯定存在问题 - 您通常希望尽快释放连接。 – Enigmativity

回答

3

适用于IQueryable<T>ToList()方法是一种扩展方法,您可以在System.core.dll中使用.NET反编译器进行查看; 如果源是ICollection<T>,则方法复制“专用阵列”,否则它将执行源的foreach循环。

IQueryable<T>的实际执行是System.Data.Entity.Infrastructure.DbQuery<TResult>而且它不是ICollection<T>

因此,ToList()基本上使用foreach复制源。

现在,它取决于实现,但使用EF内核作为示例,有一个Enumerator class,您可以看到在处理类时连接(IRelationalConnection)已关闭。 根据另一个answer和ms documentation,应尽快关闭连接以释放连接并使其在连接池中可用。

为每个唯一连接字符串创建一个连接池。创建池时,将创建多个连接对象并将其添加到池中,以满足最小池大小要求。根据需要将连接添加到池中,直到指定的最大池大小(默认为100)。连接在关闭或丢弃时释放回池中。

因此,如果您正在执行复杂的操作或执行其他查询或foreach内的其他任何内容,ToList是首选。