【问题标题】:Convert SqlDataReader to linq expression将 SqlDataReader 转换为 linq 表达式
【发布时间】:2016-03-14 19:30:16
【问题描述】:

在网上查看有关如何使用 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 执行查询?

如果我使用以下扩展方法会很糟糕吗?如果我关心性能,我应该使用第一个实现吗?

【问题讨论】:

  • 我认为性能在这里不是问题,它只是为产量生成一个状态机。除此之外,我建议公开IDataRecord 而不是IDataReader(继承),否则您将公开Read-方法(因此用户可以调用该方法并弄乱结果集)。

标签: c# performance linq sqldatareader


【解决方案1】:

您只需将IEnumerable 转换为IEnumerable&lt;IDataRecord&gt;

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

【讨论】:

  • 我很好奇,IDataReaderCast 扩展名在哪里声明? IDataReader 甚至没有声明 GetEnumerator 方法。
  • (Sql|Db)DataReader 实现 IEnumerable。而 Cast 是 System.Linq.Enumerable 中定义的扩展方法。
  • 是的,很有趣,SqlDataReader 也实现了这一点。从未使用过它,而且 MSDN 并没有清楚地说明这是当前行列的枚举数还是遍历行。我会看看它,也许将来会使用它(尽管 msdn 声明循环更可取,但不是为什么)。
  • 检查了源代码,它确实遍历了行。 +1,我喜欢它,尽管您需要小心知道 正在关闭 DbDataReader 等。
【解决方案2】:

我看不出您提议的扩展对您有什么帮助,因为对于每个读取行,您只会获得一个包含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 并将这个 pocos 与 LINQ 一起使用:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-13
    相关资源
    最近更新 更多