【问题标题】:Error reading IDataReader several times多次读取 IDataReader 时出错
【发布时间】:2012-08-07 09:09:20
【问题描述】:

我正在尝试将 SQL 数据库中的数据(1 个表中的 4 列)加载到列表中,并且到目前为止

List<string> FNameList = (from IDataRecord r in myReader
                          select (string)r["FirstName"]).ToList();

List<string> LNameList = (from IDataRecord r in myReader
                          select (string)r["LastName"]).ToList();

List<string> EmailList = (from IDataRecord r in myReader
                          select (string)r["Email"]).ToList();

List<string> PhoneList = (from IDataRecord r in myReader
                          select (string)r["PhoneNumber"]).ToList();

现在我使用的数据库有三行数据,所以每行的长度应该是 3。但是只有第一个返回长度为 3;其他的长度为0。更奇怪的是,如果我注释掉第一个,第二个会起作用,但其他的不起作用。第三个和第四个也是如此。

这很难解释,因为我无法提供用于测试的数据库,所以我想知道上面是否有任何明显的内容,或者这是否是将列数据加载到数组/列表格式的错误方法。

【问题讨论】:

  • 假设 myReader 是一个 SqlDataReader。那么这只是转发,第一次使用后不能再次重新启动
  • @Steve,这就是问题的答案

标签: c# .net sql ado.net idatareader


【解决方案1】:

我假设你有一个类似这样的Select 扩展方法:

public static IEnumerable<T> Select<T>(this IDataReader reader, Func<IDataRecord, T> selector)
{
    while(reader.Read())
        yield return selector(reader);
}

所以当reader被枚举完后,就在可用数据的末尾,再次读取数据的唯一方法就是重新发出查询。所以你需要一次获取所有字段:

var records = (from IDataRecord r in myReader
               select new
               {
                   FirstName = (string)r["FirstName"],
                   LastName = (string)r["LastName"],
                   Email = (string)r["Email"],
                   PhoneNumber = (string)r["PhoneNumber"]
               }).ToList();

【讨论】:

    【解决方案2】:

    您的阅读器在第一次查询后前进到最后一条记录。您需要提取所有行,然后构建您的列表:

    var records = (from IDataRecord r in myReader select r).ToArray();
    
    List<string> LNameList = (from IDataRecord r in records
                           select (string)r["LastName"]).ToList();
    // Keep the last row for all fields
    

    【讨论】:

    • 那行不通...它将返回最后一条记录 3 次(除非 Select 在生成数据记录之前复制它们,但这似乎不太可能)
    • ToArray 方法正在内存集合中创建 .NET。
    • 是的,但是如果Select 像我想的那样实现,它实际上总是返回相同的 IDataRecord 实例;在枚举结束时,IDataRecord 包含最后一条记录的数据。您需要在前进到下一条记录之前提取每条记录的内容。
    • 你说的听起来很有趣。打算试试看。
    • 不知道你是怎么测试的;我也对其进行了测试,并且观察到了我描述的结果。您使用了哪个 Select 实现?
    【解决方案3】:

    myReader 是一个 SqlDataReader。 SqlDataReader provides a way of reading a forward-only stream of rows from a SQL Server database。 第一次使用后无法再次重启。

    您需要在一个循环中读取所有数据,然后根据需要构建您的列表
    但是,我不明白你为什么要这样划分信息。

    【讨论】:

    • 谢谢史蒂夫,你是 100% 正确的。我对数据管理很陌生,所以我只是想让一些工作正常。托马斯的回答对我有用,所以谢谢大家!
    【解决方案4】:

    首先声明一个 poco 来保存属性:

    class Person
    {
        ...
    }
    

    然后是一个辅助方法:

    private static IEnumerable<Person> ReadReader(IDataReader reader)
    {
        using (reader)
        {
            while (reader.Read())
            {
                yield return new Person
                {
                    FirstName = (string)reader["FirstName"],
                    LastName = (string)reader["LastName"],
                    Email = (string)reader["Email"],
                    PhoneNumber = (string)reader["PhoneNumber"]
                }
            }
        }
    }
    

    用法:

    List<Person> list = RaderReader(command.ExecuteReader()).ToList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-03
      • 1970-01-01
      • 2015-04-11
      相关资源
      最近更新 更多