将SqlDataReader转换为linq表达式

6

在互联网上查看如何使用 SqlDataReader 的示例时,我发现以下内容:

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来执行查询?

如果我使用以下扩展方法,会有什么问题吗?如果我关心性能,应该使用第一个实现方法吗?


我认为性能在这里不是问题,只是需要为yield生成状态机。除此之外,我建议暴露IDataRecord而不是IDataReader(继承),否则您将暴露Read方法(因此用户可以调用该方法并弄乱结果集)。 - Caramiriel
2个回答

17

您只需要将您的IEnumerable转换为IEnumerable<IDataRecord>

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

我很好奇,这个IDataReaderCast扩展是在哪里声明的?IDataReader甚至没有声明GetEnumerator方法。 - René Vogt
1
(Sql|Db)DataReader 实现 IEnumerable 接口。而 Cast<T> 是定义在 System.Linq.Enumerable 中的扩展方法。 - Kalten
1
很有趣,SqlDataReader 也实现了这个功能。虽然我从未使用过它,而且 MSDN 也没有明确说明它是当前行列的枚举器还是遍历行的迭代器。我会去看一下它,也许将来会用到它(尽管 MSDN 表示循环更可取,但没有说明原因)。 - René Vogt
检查了源代码,它确实遍历了行。+1,我喜欢它,尽管你需要小心知道是谁关闭了DbDataReader等。 - René Vogt

3
我看不出您提出的扩展将如何帮助您,因为每次读取行时,您只会得到包含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 创建 POCO,并将其与 LINQ 一起使用:
IEnumerable<string> GetSomeColValue(IDataReader reader)
{
    while(reader.Read())
        yield return reader.GetString(reader.GetOrdinal("SomeColName"));
}

当然,这只是一个简化的示例。在实际代码中,我会完全从读取器中读取所有数据,并在返回任何内容之前在调用ExecuteReader的方法内部关闭/处理读取器实例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接