4

我有一个返回多个结果的 SQL Server 存储过程。存储过程的主体可能如下所示:

SELECT * FROM tableA;
SELECT * FROM tableB;
SELECT * FROM tableC;

在这种情况下,存储过程返回 3 个结果集。其他存储过程可能会返回例如 1、0 或任意数量的结果集。每个结果集中可能包含 0 行或更多行。加载这些时,我需要调用IDataReader.NextResult()以在结果集之间导航。

如何在 C# 中可靠地获取结果集的计数(而不是行计数)?

4

2 回答 2

10

似乎没有直接计算结果计数的属性或方法IDataReader。该接口更倾向于以增量/流式方式使用。因此,要计算返回的结果集的数量,请在每次调用时增加一个计数器,并在使用数据IDataReader.NextResult()时返回。true

但是,有一个问题。状态的文档IDataReader.NextResult()

默认情况下,数据读取器位于第一个结果上。

考虑以下场景:

  • 该命令返回 0 个结果集。您第一次调用IDataReader.NextResult()返回false
  • 该命令返回 1 个结果集。您第一次调用IDataReader.NextResult()返回false
  • 该命令返回 2 个结果集。您第二次调用IDataReader.NextResult()返回false

可以看到,只要至少有一个结果集,我们就有足够的信息来统计结果集的数量。那将是IDataReader.NextResult()返回的次数true加一。

为了检测是否有 0 个结果集,我们使用 reader 的另一个属性:IDataRecord.FieldCount. 此属性的文档指出:

当未定位在有效记录集中时,0;否则,当前记录中的列数。默认值为 -1。

因此,我们可以在第一次打开阅读器时读取该字段以确定我们是否在有效的结果集中。如果该命令未生成任何结果集,IDataRecord.FieldCount则读取器上的值最初将小于 1。如果该命令至少生成一个结果集,则该值最初将为正数。这假设结果集不可能有 0 列(我认为您可以使用 SQL 假设,不确定)。

所以,我会使用类似下面的方法来计算结果集的数量。如果您还需要保存数据,则必须在其中插入该逻辑:

using (var reader = command.ExecuteReader())
{
    var resultCount = 0;
    do
    {
        if (reader.FieldCount > 0)
            resultCount++;

        while (reader.Read())
        {
            // Insert logic to actually consume data here…
            // HandleRecordByResultIndex(resultCount - 1, (IDataRecord)reader);
        }
    } while (reader.NextResult());
}

我已经使用System.Data.SqlClient命令PRINT 'hi'(0 个结果集)、SELECT 1 x WHERE 1=0(1 个结果集)和SELECT 1 x WHERE 1=0; SELECT 1 x WHERE 1=0(2 个结果集)对此进行了测试。

于 2016-10-14T00:53:56.370 回答
7

用于DataReader.NextResult将阅读器推进到下一个结果集。:

using (var con = new SqlConnection(Properties.Settings.Default.ConnectionString))
{
    using (var cmd = new SqlCommand("SELECT * FROM TableA; SELECT * FROM TableB; SELECT * FROM TableC;", con))
    {
        con.Open();
        using (IDataReader rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
            {
                int firstIntCol = rdr.GetInt32(0); // assuming the first column is of type Int32
                // other fields ...
            }
            if (rdr.NextResult())
            {
                while (rdr.Read())
                {
                    int firstIntCol = rdr.GetInt32(0); // assuming the first column is of type Int32
                    // other fields ...
                }
                if (rdr.NextResult())
                {
                    while (rdr.Read())
                    {
                        int firstIntCol = rdr.GetInt32(0); // assuming the first column is of type Int32
                        // other fields ...
                    }
                }
            }
        }
    }
}
于 2013-08-08T10:00:38.817 回答