2013-08-08 2 views
3

У меня есть хранимая процедура SQL Server, которая возвращает несколько результатов. Тело хранимой процедуры может выглядеть так:Получить количество результирующих наборов из SqlDataReader

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

В этом случае хранимая процедура возвращает 3 набора результатов. Другие хранимые процедуры могут возвращаться, например, 1, 0 или любое количество наборов результатов. Каждый набор результатов может содержать 0 или более строк. При загрузке этих данных мне нужно будет позвонить IDataReader.NextResult() для перемещения между наборами результатов.

Как я могу надежно получить количество наборов результатов (а не число строк) в C#?

+0

Что вы имеете в виду с подсчетом, количеством результирующих наборов или количеством подсчетов каждой строки? –

+0

Процитировать результат результата от всех избранных, как он сказал. – butterbox

+1

Я имею в виду подсчет результатов (над деревом). каждый набор может содержать несколько строк. – isxaker

ответ

6

Использование 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 ... 
        } 
       } 
      } 
     } 
    } 
} 
+0

if (rdr.NextResult()) count ++; у тебя есть идеи? метод NextResult() переместить позицию sqldatareader – isxaker

+1

@Mikhail: Объясните свой вопрос. Нужно ли подсчет строк каждой таблицы или вам нужно количество наборов результатов или вам нужны строки каждого набора результатов (как показано выше)? Если вам просто нужно количество наборов результатов: 'int count = 0; while (rdr.NextResult()) count ++; 'должен работать. –

+2

Хорошо, если я использую этот метод, как я могу вернуть позицию sqldatareader перед первой записью после подсчета? – isxaker

6

Там, кажется, нет никакой собственности или метод, который непосредственно вычисляет количество результатов в IDataReader. Этот интерфейс скорее намерен потребляться инкрементным/потоковым способом. Таким образом, чтобы подсчитать количество возвращаемых наборов результатов, увеличивайте счетчик каждый раз, когда вы вызываете IDataReader.NextResult(), и он возвращает true при потреблении данных.

Однако есть улов. документация для IDataReader.NextResult() состояний:

По умолчанию считыватель данных устанавливается на первый результат.

Рассмотрим следующие сценарии:

  • Команда возвращается 0 наборов результатов. Ваш первый звонок IDataReader.NextResult() возвращает false.
  • Команда вернула 1 результирующий набор. Ваш первый звонок IDataReader.NextResult() возвращает false.
  • Команда вернула 2 набора результатов. Ваш второй звонок IDataReader.NextResult() возвращает false.

Вы можете видеть, что у нас достаточно информации для подсчета количества наборов результатов, пока существует хотя бы один результирующий набор. Это будет количество раз, которое IDataReader.NextResult() возвращено true плюс один.

Для определения наличия или отсутствия 0 наборов результатов мы используем другое свойство от читателя: 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 набора результатов).

+1

В зависимости от сценария я также использовал 'SqlDataReader.HasRows' вместо' FieldCount' (я, вероятно, чаще использовал 'HasRows', чем' FieldCount'). Но да, 'do {...} while()' намного лучше (и более чистый) подход, чем запутанный и менее гибкий подход, показанный в принятом ответе. (+1). И правильно, результирующий набор должен иметь хотя бы один столбец. –

+0

@srutzky Код, который я написал, вероятно, никогда не будет чем-то другим, кроме 'System.Data.SqlClient', и у меня нет абстракции над сырым T-SQL, но мне все же кажется забавным пытаться ограничиться доступными интерфейсами (за исключением использования совместимых с TPL 'Async()' вариантов, для которых я использую 'DbCommand'). 'FieldCount' чувствует себя взломанным, но, по крайней мере, я могу получить« чистый »код взаимозависимости ;-) – binki

Смежные вопросы