问候,我有以下问题。我没有找到它的确切答案,这对我来说真的很有趣。假设我有以下代码从数据库中检索记录(例如,为了将其导出到XML文件)。
var result = from emps in dc.Employees
where emps.age > 21
select emps;
foreach (var emp in result) {
// Append this record in suitable format to the end of XML file
}
假设有一百万条记录满足代码中的 where 条件。会发生什么?所有这些数据将在到达 foreach 构造时立即从SQL Server检索到运行时内存,或者在必要时检索它,第一个记录,第二个。换句话说,LINQ是否真的通过迭代大型集合来处理这种情况(详情请参阅我的post)?
如果没有,那么如何克服内存问题呢?如果我真的需要遍历大集合,我该怎么办?借助Count函数计算集合中元素的实际数量,然后按小部分从数据库中读取数据。有没有一种简单的方法来实现LINQ框架的分页?
答案 0 :(得分:10)
将一次从SQL Server检索所有数据,并将其放入内存。我能想到的唯一解决方法是以较小的块处理数据(如使用Skip()和Take()的页面。但是,当然,这需要更多的SQL Server命中。
这是我写的Linq分页扩展方法:
public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, int pageNumber, int pageSize)
{
return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
}
答案 1 :(得分:5)
是的,LINQ使用延迟评估。当foreach开始执行时,将查询数据库,但它会一次性获取所有数据(一次只能为一个结果执行数百万次查询效率低得多)。
如果您担心一次性引入太多结果,您可以使用Skip和Top一次只获得有限数量的结果(从而对结果进行分页)。
答案 2 :(得分:1)
当您调用ToList或类似方法时,它将被检索。 LINQ延迟执行:
方法 - 即使延迟执行并在OR / M或任何其他LINQ提供程序的情况下从数据源加载整个集合 - 将由LINQ对象源的实现者确定。
例如,某些OR / M可能会提供延迟加载,这意味着您的“整个客户列表”将类似于游标,并访问其中一个项目(一个员工),还有一个属性,将仅加载员工本身或被访问的财产。
但是,无论如何,这些都是基础。
编辑:现在我看到它是一个LINQ-to-SQL的东西...或者我不知道问题的作者是否误解了LINQ并且他不知道LINQ不是LINQ-to-SQL,但它更像是模式和语言特征。答案 3 :(得分:0)
好的,现在感谢answer我有一个想法 - 如何将页面功能与收益率回报的可能性混合起来?以下是代码示例:
// This is the original function that takes the page
public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, int pageNumber, int pageSize) {
return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
}
// And here is the function with yield implementation
public static IEnumerable<TSource> Lazy<TSource>(this IEnumerable<TSource> source, int pageSize) {
int pageNumber = 1;
int count = 0;
do {
IEnumerable<TSource> coll = Page(source, pageNumber, pageSize);
count = coll.Count();
pageNumber++;
yield return coll;
} while (count > 0);
}
// And here goes our code for traversing collection with paging and foreach
var result = from emps in dc.Employees
where emps.age > 21
select emps;
// Let's use the 1000 page size
foreach (var emp in Lazy(result, 1000)) {
// Append this record in suitable format to the end of XML file
}
我认为这样我们可以克服内存问题,但是 foreach 的结构不会那么复杂。