2016-03-14 41 views
1

当如何使用SqlDataReader在互联网上的例子看,我发现的东西,如:转换SqlDataReader对象到LINQ表达

var command = new SqlCommand( // initialize with query and connection... 
var reader = command.ExecuteReader(); 

while(reader.Read()) 
{ 
    var foo = reader["SomeColName"]; 
    // etc 
} 

我可以使用下面的扩展方法:

public static IEnumerable<IDataReader> ToEnumerable(this IDataReader reader) 
{ 
    while (reader.Read())    
     yield return reader;    
} 

为了使用linq执行查询?

如果我使用下面的扩展方法会不好?如果我关心性能,我应该使用第一个实现吗?

+0

我认为表现不会是一个问题在这里,它只是产生一个状态机的产量。除此之外,我建议公开'IDataRecord'而不是'IDataReader'(继承),否则你会暴露'Read'方法(所以用户可以调用该方法并弄乱结果集)。 – Caramiriel

回答

1

我看不出您的建议扩展程序如何帮助您,因为您只针对每个读取行获得包含相同实例的IDataReader的枚举。

我不知道如果有IDataReader与LINQ结合什么好办法,但你可能希望这样的事情:

public static IEnumerable<Dictionary<string, object>> ToEnumerable(this IDataReader reader) 
{ 
    while (reader.Read()) 
    { 
     Dictionary<string, object> result = new Dictionary<string, object>(); 
     for (int column = 0; column < reader.FieldCount; column++) 
      result.Add(reader.GetName(column), reader.GetValue(column)); 
     yield return result; 
    } 
} 

这将返回字典的序列(每行一个词典),其将列名映射到该“单元”中的对象。不幸的是,你失去了类型安全并且造成了内存开销。具体的实施仍然取决于你真正想要达到的目标。就个人而言,我总是只使用列索引而不是名称。


这么说,我认为最好的办法还是使用IDataReader直接创造波苏斯和使用该POCOS与LINQ:

IEnumerable<string> GetSomeColValue(IDataReader reader) 
{ 
    while(reader.Read()) 
     yield return reader.GetString(reader.GetOrdinal("SomeColName")); 
} 

当然,这是一个缩短的例子。在实际代码中,我会完全读出来自阅读器的所有数据,并在返回任何内容之前将阅读器实例放置在调用ExecuteReader的方法内。

5

你只需要投你IEnumerableIEnumerable<IDataRecord>

var enumerable = reader.Cast<IDataRecord>(); 
var col = enumerable.Select(record => record .GetOrdinal("SomeColName")); 
+0

我很好奇,这个'IDataReader'的'Cast'扩展名在哪里声明? 'IDataReader'甚至没有声明'GetEnumerator'方法。 –

+0

(Sql | Db)DataReader实现IEnumerable。而Cast 是System.Linq.Enumerable中定义的扩展方法。 – Kalten

+0

有趣的是,'SqlDataReader'也实现了这一点。从未使用过,MSDN也没有清楚地说明这是否是当前行列的枚举器,或者是否遍历行。我会看看它,并可能在未来使用它(尽管msdn指出循环是可取的,但不是为什么)。 –