从SqlDataReader返回延迟数据

时间:2015-02-23 17:13:34

标签: c# .net lazy-loading lazy-evaluation sqldatareader

问题:我要从数据库中处理数百万行。

我需要实现一个返回数据库行的"流"(?)的方法。 我不想立刻将所有内容加载到内存中。

我正在考虑返回一个懒惰的IEnumerable<Record>并使用yield。 该方法将使用SqlDataReader处理连续记录。

但是当客户在.Count()上拨打IEnumerable时会发生什么?计算所有记录意味着需要全部获取它们。

有没有什么好的现代方法可以返回一个没有将所有对象存储在内存中的对象流,只需逐个处理?我的方法应该返回一个记录流。

似乎Reactive Extensions可能会为我解决问题,但我从未使用它。

有什么想法吗?

由于

2 个答案:

答案 0 :(得分:2)

首先,为什么重新发明轮子?实体框架使得更容易做到这样的事情并为您添加所有抽象。 DbSet<TEntity>对象上的DbContext实现了IQueryable<TEntity>IEnumerable<T>,因此您可以:

  • 当您需要计算记录数(或其他一些聚合函数)时,使用扩展方法执行Count()(带和不带lamda过滤器参数)
  • 您可以将它们作为IEnumerable循环遍历,它可以在每次从连接调用MoveNext方法时打开连接并一次读取1条记录。
  • 如果您确实希望一次将所有内容加载到内存中(我知道您不是基于您的描述),您可以调用扩展方法ToList或ToArray。

如果你坚持使用ADO.NET并手动执行此操作(我理解遗留代码并不总是可以选择使用EF),那么从连接中打开数据读取器是最好的方法。这将在每个下一个记录中读取每个对应的方法Read()的调用,这是在DB中读取记录的最便宜的方法。

如果你想要一个Count,那么我建议你写一个新的sql查询,它返回一个使用Sql在数据库服务器上执行的计数

SELECT COUNT(field) FROM table 

因为这是最佳做法。不要迭代并总结读者的所有记录,并通过一些自定义的工作来执行内存中的总和,这将浪费资源,更不用说创建复杂的代码而没有任何好处。

答案 1 :(得分:0)

对于count查询db,并返回给用户。

另一方面,您只需要为ICollection实现count,IEnumerable不需要。只需返回IEnumerable以便对记录进行迭代。

请注意,您正确处理了与db的连接。