使用IDataReader作为IEnumerable 的最佳方法?

我需要在任何像这样的IDataReader实现上使用Linq

var c = sqlDataReader.AsEnumerable().Count(); 

例:

 public abstract class Test { public abstract SqlDataReader GetSqlDataReader(); public void Foo() { SqlDataReader sqlDataReader = GetSqlDataReader(); IEnumerable sqlEnumerable = sqlDataReader.AsEnumerable(); var c = sqlEnumerable.Count(); var s = sqlEnumerable.Sum(); SqlDataReader first = sqlEnumerable.First(); var t = first.GetSqlXml(10); } } 

写这个的最好方法是什么。 请写下你的代码片段。

试试这个:

 public static class DataReaderExtension { public class EnumeratorWrapper { private readonly Func moveNext; private readonly Func current; public EnumeratorWrapper(Func moveNext, Func current) { this.moveNext = moveNext; this.current = current; } public EnumeratorWrapper GetEnumerator() { return this; } public bool MoveNext() { return moveNext(); } public T Current { get { return current(); } } } private static IEnumerable BuildEnumerable( Func moveNext, Func current) { var po = new EnumeratorWrapper(moveNext, current); foreach (var s in po) yield return s; } public static IEnumerable AsEnumerable(this T source) where T : IDataReader { return BuildEnumerable(source.Read, () => source); } } 

你可以用这个:

 MyDataReader.Cast() 

但是在关闭DataReader之前不要忘记执行linq语句。
例如,使用ToList()

您可以创建一个扩展方法来执行此操作(请参阅下面的注意事项)

 public static class DataReaderExtension { public static IEnumerable AsEnumerable(this System.Data.IDataReader source) { if (source == null) throw new ArgumentNullException("source"); while (source.Read()) { Object[] row = new Object[source.FieldCount]; source.GetValues(row); yield return row; } } } 

在这里找到: http : //www.thinqlinq.com/default/Consuming-a ChallReader-with- LINQ.aspx


正如@LukeH指出的那样,请注意,由于IDataReader仅支持一次转发,因此您只能查询一次可枚举数。 (为了解决这个问题,你可以调用ToList / ToArray,然后查询)。

请注意, SqlDataReader已经实现了IEnumerable,因此您不需要在您给出的示例中执行此操作。

另外,请注意,在服务器上进行任何过滤/聚合可能更好(例如,通过LINQ to SQL )

这是我的两分钱:

 public static IEnumerable Enumerate(this T reader) where T: IDataReader { using(reader) while(reader.Read()) yield return reader; } public void Test() { var Res = from Dr in MyDataReader.Enumerate() select new { ID = (Guid)Dr["ID"], Description = Dr["Desc"] as string }; } 

我觉得发布这个的冲动,因为在使用后处理DataReader非常重要,没有回答提到它。

这就是为什么我的实现在while循环中有一个using语句。 通过这种方式,我可以进行“单手”查询而无需担心DataReader处理。

您可以将DataReader加载到DataTable ,然后Select()

 DataTable dt = new DataTable(); dt.Load(dataReader); DataRow[] rows = dt.Select(); //DataRow[] Implements IEnumerable 

要么

 IEnumerable rows = dt.AsEnumerable(); 

我已经使用了以下内容,但我更喜欢@ Serge的建议,它让人想起我相信以前做的事情,但后来却忘记了IDataReader的实现

 var reader = command.ExecuteReader(); var records = Enumerable .Range(0, int.MaxValue) .TakeWhile(i => reader.Read()) .Select(i => reader as IDataRecord);