我有一个返回多个结果的SQL Server存储过程。存储过程的主体可能如下所示:
SELECT * FROM tableA;
SELECT * FROM tableB;
SELECT * FROM tableC;
在这种情况下,存储过程返回3个结果集,其他存储过程可能返回1、0或任意数量的结果集,每个结果集可能包含0行或更多行,在加载这些结果集时,我需要调用IDataReader.NextResult()
在结果集之间导航。
如何在C#中可靠地获得结果集的计数(而不是行计数)?
我有一个返回多个结果的SQL Server存储过程。存储过程的主体可能如下所示:
SELECT * FROM tableA;
SELECT * FROM tableB;
SELECT * FROM tableC;
在这种情况下,存储过程返回3个结果集,其他存储过程可能返回1、0或任意数量的结果集,每个结果集可能包含0行或更多行,在加载这些结果集时,我需要调用IDataReader.NextResult()
在结果集之间导航。
如何在C#中可靠地获得结果集的计数(而不是行计数)?
3条答案
按热度按时间jfewjypa1#
IDataReader
中似乎没有直接计算结果计数的属性或方法。该接口更倾向于以增量/流方式使用。因此,要计算返回的结果集的数量,每次调用IDataReader.NextResult()
时都递增计数器,它在使用数据时返回true
。但是,有一个陷阱。
IDataReader.NextResult()
的文档指出:默认情况下,数据读取器定位在第一个结果上。
请考虑以下情形:
IDataReader.NextResult()
时返回false
。IDataReader.NextResult()
时返回false
。IDataReader.NextResult()
将返回false
。可以看到,只要至少有一个结果集,我们就有足够的信息来计算结果集的数量,即
IDataReader.NextResult()
返回true
的次数加1。为了检测是否存在0个结果集,我们使用读取器中的另一个属性:
IDataRecord.FieldCount
。此属性的文档说明:未定位在有效记录集中时,为0;否则返回当前记录中的列数。默认值为-1。
因此,我们可以在第一次打开读取器时读取该字段,以确定我们是否在有效的结果集中。如果命令未生成结果集,则读取器上
IDataRecord.FieldCount
的值最初将小于1。如果命令至少生成一个结果集,这个值最初是正的。2这是假设一个结果集不可能有0列(我想你可以用SQL来假设,不确定)。因此,我将使用类似下面的代码来计算结果集的数量。如果您还需要保存数据,则必须将该逻辑插入到该代码中:
我已经用
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个结果集)对此进行了测试。dzjeubhm2#
使用
DataReader.NextResult
将读取器前进到下一个结果集。注意:xdyibdwo3#
除了手动
SqlDataReader
方法之外,在可接受的答案中,另一个需要注意的解决方案是使用SqlDataAdapter
、DataSet
和DataTable
。当使用这些类时,整个结果集从服务器中一次检索出来,您可以在空闲时迭代它们。另外,如果您还设置了
DeleteCommand
、InsertCommand
和UpdateCommand
属性,其他几个.net类也可以识别DataSet和DataTable,并且可以直接连接到它们,以进行只读或读写数据访问。“的功能是更改DataSet
中的数据,然后只需调用Update()
将本地更改推送到数据库。您还获得了RowUpdated
事件处理程序,可以使用它自动执行此操作。DataSet
s和DataTable
s也保留了数据库模式中的元数据,因此您仍然可以根据自己的喜好按名称或索引访问列。总的来说,它们是一个很好的特性,尽管肯定比
SqlDataReader
更重。SqlDataAdapter
的文档如下:https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqldataadapter