C# 将IDataReader用作IEnumerable的最佳方法<;T>;?
我需要在任何像这样的IDataReader实现上使用LinqC# 将IDataReader用作IEnumerable的最佳方法<;T>;?,c#,.net,extension-methods,ienumerable,C#,.net,Extension Methods,Ienumerable,我需要在任何像这样的IDataReader实现上使用Linq var c = sqlDataReader.AsEnumerable().Count(); 例如: public abstract class Test { public abstract SqlDataReader GetSqlDataReader(); public void Foo() { SqlDataReader sqlDataReader = GetSqlDataReader()
var c = sqlDataReader.AsEnumerable().Count();
例如:
public abstract class Test
{
public abstract SqlDataReader GetSqlDataReader();
public void Foo()
{
SqlDataReader sqlDataReader = GetSqlDataReader();
IEnumerable<SqlDataReader> sqlEnumerable = sqlDataReader.AsEnumerable();
var c = sqlEnumerable.Count();
var s = sqlEnumerable.Sum();
SqlDataReader first = sqlEnumerable.First();
var t = first.GetSqlXml(10);
}
}
公共抽象类测试
{
公共抽象SqlDataReader GetSqlDataReader();
公共图书馆
{
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 static IEnumerable<Object[]> 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;
}
}
}
公共静态类DataReaderExtension
{
公共静态IEnumerable AsEnumerable(此System.Data.IDataReader源)
{
if(source==null)
抛出新的ArgumentNullException(“源”);
while(source.Read())
{
Object[]行=新对象[source.FieldCount];
source.GetValues(行);
收益返回行;
}
}
}
可在此处找到:
正如@LukeH所指出的,请注意,由于IDataReader只支持读取一次,所以只能查询一次可枚举项。(要解决这个问题,可以调用ToList/ToArray,然后查询该问题) 请注意,
SqlDataReader
已经实现了IEnumerable,因此在您给出的示例中不需要这样做
另外,请注意,最好在服务器上进行任何筛选/聚合(例如通过)尝试以下操作:
public static class DataReaderExtension
{
public class EnumeratorWrapper<T>
{
private readonly Func<bool> moveNext;
private readonly Func<T> current;
public EnumeratorWrapper(Func<bool> moveNext, Func<T> current)
{
this.moveNext = moveNext;
this.current = current;
}
public EnumeratorWrapper<T> GetEnumerator()
{
return this;
}
public bool MoveNext()
{
return moveNext();
}
public T Current
{
get { return current(); }
}
}
private static IEnumerable<T> BuildEnumerable<T>(
Func<bool> moveNext, Func<T> current)
{
var po = new EnumeratorWrapper<T>(moveNext, current);
foreach (var s in po)
yield return s;
}
public static IEnumerable<T> AsEnumerable<T>(this T source) where T : IDataReader
{
return BuildEnumerable(source.Read, () => source);
}
}
公共静态类DataReaderExtension
{
公共类枚举器包装器
{
私有只读Func moveNext;
私有只读函数当前;
公共枚举器包装器(Func moveNext,Func current)
{
this.moveNext=moveNext;
这个电流=电流;
}
公共枚举器包装器GetEnumerator()
{
归还这个;
}
公共图书馆
{
返回moveNext();
}
公共电流
{
获取{返回当前();}
}
}
私有静态IEnumerable BuildEnumerable(
Func moveNext,Func current)
{
var po=新的枚举器包装器(moveNext,current);
foreach(采购订单中的var s)
收益率;
}
公共静态IEnumerable AsEnumerable(此T源),其中T:IDataReader
{
返回BuildEnumerable(source.Read,()=>source);
}
}
您可以使用以下功能:
MyDataReader.Cast<IDataRecord>()
MyDataReader.Cast()
但是不要忘记在关闭DataReader之前执行linq语句。
例如,使用ToList()您只需将
数据读取器
加载到数据表
中,然后选择()
:
或
IEnumerable rows=dt.AsEnumerable();
这是我的两分钱:
public static IEnumerable<T> Enumerate<T>(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
};
}
公共静态IEnumerable枚举(此T读取器),其中T:IDataReader
{
使用(读卡器)
while(reader.Read())
回传阅读器;
}
公开无效测试()
{
var Res=
从MyDataReader.Enumerate()中的Dr
选择新的{
ID=(Guid)Dr[“ID”],
Description=Dr[“Desc”]作为字符串
};
}
我迫不及待地想发布这篇文章,因为在使用后处理DataReader
是非常重要的,没有人提到它
这就是为什么我的实现在
while
循环中使用语句的原因。通过这种方式,我可以进行“单手”查询,而不必担心数据阅读器的处理。我使用了以下方法,但我更喜欢@Serge的建议,它让我想起了我相信我曾经做过的事情,但后来忘了IDataReader实现了
var reader = command.ExecuteReader();
var records = Enumerable
.Range(0, int.MaxValue)
.TakeWhile(i => reader.Read())
.Select(i => reader as IDataRecord);
请注意,这将不允许他们像示例中那样先进行计数
,然后进行求和
,然后进行第一次
。(尽管要做到这一点,他们要么需要重新查询数据库三次,要么以某种方式缓冲结果,两者都有潜在的缺陷。)@George Duckett“请注意,SqlDataReader已经实现了IEnumerable,因此在您给出的示例中不需要这样做。”,是的,这是正确的,但我需要IEnumerable来使用示例方法“GetSqlXml”“IEnumerable AsEnumerable”,我需要IEnumerable“您只能查询可枚举的一次”我知道,但我可以使用“AsQueryable()“要做到这一点,@b2Lord,IEnumerable
没有意义,因为您只有一个SqlDataReader
,您没有枚举多个SqlDataReader
。嗨,Gabriel。您似乎有两个帐户(,)。如果您希望链接它们,请按照下面的步骤进行操作,因为对于您的代码来说似乎没有问题,但是对于更复杂的表,可能会出现错误,从而停止迭代,并且永远不会处理读取器。我遇到了这个问题,我创建了一个“DisposableEnumerable”类,以便在Enumerate方法之外进行使用,并在出现问题时调用Dispose。+1用于提出关于using
语句的建议以及关闭datareader的重要性。在某些环境中,DataReader实际上可以锁定数据库、表、叶等。
public static IEnumerable<T> Enumerate<T>(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
};
}
var reader = command.ExecuteReader();
var records = Enumerable
.Range(0, int.MaxValue)
.TakeWhile(i => reader.Read())
.Select(i => reader as IDataRecord);