如何在C#中使用SqlDataReader获取行数

Tom*_*icz 93 c# sqldatareader

我的问题是如何SqlDataReader在C#中获取查询返回的行数.我已经看到了一些关于此的答案,但没有明确定义,除了一个声明用Read()方法做一个while循环并增加一个计数器.

我的问题是我试图填充一个多维数组,第一行是列标题名称,后面的每一行都是行数据.

我知道我可以将这些东西转储到List控件中而不用担心它,但是对于我自己的个人启发,我还想在我选择的时候将数据拉入和拉出阵列,并以不同的格式显示它.

所以我认为我不能这样做Read()然后增加++方式,因为这意味着我必须打开Read()然后Read()再次打开以获得行数然后列数据.

只是我正在谈论的一个小例子:

int counter = 0;    

while (sqlRead.Read())
{
    //get rows
    counter++
}
Run Code Online (Sandbox Code Playgroud)

然后一个for循环运行列和弹出

something.Read();

int dbFields = sqlRead.FieldCount;

for (int i = 0; i < dbFields; i++)
{
   // do stuff to array
}
Run Code Online (Sandbox Code Playgroud)

Hen*_*man 93

只有两个选择:

  • 通过阅读所有行找出(然后你也可以存储它们)

  • 事先运行专门的SELECT COUNT(*)查询.

两次通过DataReader循环非常昂贵,您必须重新执行查询.

并且(感谢Pete OHanlon)当您使用具有Snapshot隔离级别的事务时,第二个选项仅是并发安全的.

由于您最终想要将所有行存储在内存中,唯一明智的选择是读取灵活存储(List<>DataTable)中的所有行,然后将数据复制到您想要的任何格式.内存中的操作总是更有效率.

  • 专门计数的问题在于,计数可能与返回的行数不同,因为其他人已经以导致返回行数的方式更改了数据. (13认同)
  • Henk是对的:没有DataReader的成员允许你获得行数,因为它是一个前向读者.您最好首先获取计数然后执行查询,可能在多结果查询中,因此您只需访问数据库一次. (4认同)
  • `RepeatableRead`隔离级别不执行范围锁定,因此它仍然允许插入记录,您需要使用隔离级别的"快照"或"可序列化". (3认同)

Pit*_*ing 8

如果您不需要检索所有行并且想要避免进行双重查询,那么您可以尝试这样的事情:

using (var sqlCon = new SqlConnection("Server=127.0.0.1;Database=MyDb;User Id=Me;Password=glop;"))
      {
        sqlCon.Open();

        var com = sqlCon.CreateCommand();
        com.CommandText = "select * from BigTable";
        using (var reader = com.ExecuteReader())
        {
            //here you retrieve what you need
        }

        com.CommandText = "select @@ROWCOUNT";
        var totalRow = com.ExecuteScalar();

        sqlCon.Close();
      }
Run Code Online (Sandbox Code Playgroud)

您可能必须添加一个事务,不确定重用相同的命令是否会自动添加一个事务...

  • 如果我们在从读取器检索数据之前需要行计数,它将不起作用 (2认同)

小智 6

如上所述,数据集或类型化数据集可能是一个很好的临时结构,您可以使用它来进行过滤.SqlDataReader旨在非常快速地读取数据.当你在while()循环中时,你仍然连接到数据库,它正在等待你做任何你正在做的事情,以便在它继续前读取/处理下一个结果.在这种情况下,如果您提取所有数据,关闭与数据库的连接并"离线"处理结果,您可能会获得更好的性能.

人们似乎讨厌数据集,所以上面也可以用强类型对象的集合来完成.

  • 丹尼尔,'上面'不是一个引用另一个答案的好方法. (4认同)
  • 我自己喜欢 DataSet,因为它们是基于表的数据的一种编写良好且非常有用的通用表示。奇怪的是,我注意到大多数避开 ORM 的 DataSet 的人都是试图编写自己的代码以使其尽可能通用(通常毫无意义)的人。 (2认同)

Pet*_*lon 5

您无法直接从数据读取器中获取行数,因为这就是所谓的流水光标(firehose cursor)-这意味着将基于执行的读取逐行读取数据。我建议不要对数据进行2次读取,因为在进行2次读取之间数据可能会发生变化,因此您会得到不同的结果。

您可以做的是将数据读取到一个临时结构中,并用它代替第二次读取。另外,您将需要更改检索数据的机制,并改用DataTable之类的方法。


meh*_*hdi 5

完成 Pit 答案并获得更好的性能:在一个查询中获取所有内容并使用 NextResult 方法。

using (var sqlCon = new SqlConnection("Server=127.0.0.1;Database=MyDb;User Id=Me;Password=glop;"))
{
    sqlCon.Open();
    var com = sqlCon.CreateCommand();
    com.CommandText = "select * from BigTable;select @@ROWCOUNT;";
    using (var reader = com.ExecuteReader())
    {
        while(reader.Read()){
            //iterate code
        }
        int totalRow = 0 ;
        reader.NextResult();
        if(reader.Read()){
            totalRow = (int)reader[0];
        }
    }
    sqlCon.Close();
}
Run Code Online (Sandbox Code Playgroud)