Как получить количество строк, используя SqlDataReader в С#

Мой вопрос заключается в том, как получить количество строк, возвращаемых запросом, используя SqlDataReader в С#. Я видел некоторые ответы об этом, но ни один из них не был четко определен, кроме одного, который заявляет, чтобы сделать цикл while с помощью метода Read() и увеличивать счетчик.

Моя проблема заключается в том, что я пытаюсь заполнить многомерный массив первой строкой, являющейся именами заголовка столбца, и каждой строкой после этого, чтобы быть данными строки.

Я знаю, что могу просто сбрасывать материал в элементе управления List и не беспокоиться об этом, но для собственного личного назидания, и я также хотел бы вытащить данные из массива и из него по мере выбора и отображения его в в разных форматах.

Поэтому я думаю, что не могу сделать Read(), а затем increment ++ way, потому что это означает, что мне нужно будет открыть Read(), а затем снова открыть Read(), чтобы получить количество строк, а затем данные столбца.

Небольшой пример того, что я говорю:

int counter = 0;    

while (sqlRead.Read())
{
    //get rows
    counter++
}

а затем цикл for для запуска через столбцы и pop

something.Read();

int dbFields = sqlRead.FieldCount;

for (int i = 0; i < dbFields; i++)
{
   // do stuff to array
}

Ответ 1

Есть только два варианта:

  • Узнайте, прочитав все строки (и затем вы также сохраните их)

  • запустите специальный запрос SELECT COUNT (*) заранее.

Переход дважды через цикл DataReader очень дорог, вам придется повторно выполнить запрос.

И (спасибо Pete OHanlon) второй вариант - это только concurrency -безопасно, когда вы используете транзакцию с уровнем изоляции моментального снимка.

Поскольку вы хотите в конечном итоге сохранить все строки в памяти, в любом случае единственной разумной опцией является чтение всех строк в гибком хранилище (List<> или DataTable), а затем копирование данных в любой формат. Операция в памяти всегда будет намного более эффективной.

Ответ 2

Реляционные классы /DataSet являются подходящей опцией.

using (DataTable dt = new DataTable())
 {
  dt.Load(sqlRead);
  Console.WriteLine(dt.Rows.Count);
}

Ответ 3

В приведенном выше наборе данных или типизированном наборе данных может быть хорошая структура temorary, которую вы могли бы использовать для фильтрации. SqlDataReader предназначен для быстрого считывания данных. Пока вы находитесь в цикле while(), вы все еще подключены к БД, и он ждет, когда вы будете делать все, что вы делаете, чтобы читать/обрабатывать следующий результат до его перемещения. В этом случае вы можете получить более высокую производительность, если потянете все данные, закройте соединение с БД и обработайте результаты "в автономном режиме".

Люди, похоже, ненавидят наборы данных, поэтому вышеупомянутое может быть сделано с помощью набора строго типизированных объектов.

Ответ 4

Если вам не нужно извлекать всю строку и вы хотите избежать двойного запроса, возможно, вы можете попробовать что-то вроде этого:

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();
      }

Возможно, вам придется добавить транзакцию не уверен, что повторное использование одной и той же команды автоматически добавит на нее транзакцию...

Ответ 5

Вы не можете получить количество строк непосредственно из устройства чтения данных, потому что это то, что известно как курсор firehose, что означает, что данные считываются последовательно по строкам на основе выполняемого чтения. Я бы посоветовал не делать 2 чтения данных, потому что существует вероятность того, что данные изменились между двумя чтениями, и, следовательно, вы получите разные результаты.

Что вы можете сделать, это прочитать данные во временную структуру и использовать это вместо второго чтения. Кроме того, вам необходимо изменить механизм, с помощью которого вы извлекаете данные, и вместо этого используйте что-то вроде DataTable.

Ответ 6

Я также сталкиваюсь с ситуацией, когда мне нужно вернуть верхний результат, но также хотел получить общие строки, которые соответствуют запросу. я окончательно доберусь до этого решения:

   public string Format(SelectQuery selectQuery)
    {
      string result;

      if (string.IsNullOrWhiteSpace(selectQuery.WherePart))
      {
        result = string.Format(
@"
declare @maxResult  int;
set @maxResult = {0};

WITH Total AS
(
SELECT count(*) as [Count] FROM {2}
)
SELECT top (@maxResult) Total.[Count], {1} FROM Total, {2}", m_limit.To, selectQuery.SelectPart, selectQuery.FromPart);
      }
      else
      {
        result = string.Format(
@"
declare @maxResult  int;
set @maxResult = {0};

WITH Total AS
(
SELECT count(*) as [Count] FROM {2} WHERE {3}
)
SELECT top (@maxResult) Total.[Count], {1} FROM Total, {2} WHERE {3}", m_limit.To, selectQuery.SelectPart, selectQuery.FromPart, selectQuery.WherePart);
      }

      if (!string.IsNullOrWhiteSpace(selectQuery.OrderPart))
        result = string.Format("{0} ORDER BY {1}", result, selectQuery.OrderPart);

      return result;
    }