2009-09-05 2 views
79

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

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

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

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

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

int counter = 0;  

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

, а затем цикл для запуска через колонки и поп

something.Read(); 

int dbFields = sqlRead.FieldCount; 

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

ответ

75

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

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

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

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

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

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

+4

Хенк прав: в DataReader нет члена, который позволяет вам получить количество строк, потому что это читатель с прямым доступом. Вам лучше сначала сделать счет, а затем выполнить запрос, возможно, в результате запроса с несколькими результатами, чтобы вы только попали в базу данных один раз. – flipdoubt

+12

Проблема со специализированным подсчетом заключается в том, что существует вероятность того, что счет отличается от числа возвращенных строк, потому что кто-то другой изменил данные таким образом, который приводит к количеству возвращаемых строк. –

+0

Пит, вы правы, для этого потребуется дорогостоящий IsolationLevel. –

4

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

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

6

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

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

+1

Мне очень нравятся DataSets, поскольку они представляют собой хорошо написанное и чрезвычайно полезное общее представление табличных данных. Как ни странно, я заметил, что большинство людей, которые избегают DataSet для ORM, - это те же люди, которые пытаются написать свой собственный код как можно более общий (как правило, бессмысленно). – MusiGenesis

+4

Daniel, 'above' не является хорошим способом ссылки на другой ответ. –

17

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

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

Загрузка всех данных, чтобы получить количество строк, не очень хорошая идея. Особенно в DataTable, что приведет к нехватке памяти ошибок. – shatl

+0

@shatl - Согласен! но этот вариант предлагается многими плакатами, включая Хенка Холтермана, и я думаю, что OP хотел убедиться, что нет никакого прямого метода, который возвращает количество строк. – adatapost

+1

@AVD DataTable - это тяжелый вес, чтобы получить количество строк. –

5

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

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

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

+0

Любой может сказать, что если @@ ROWCOUNT всегда полагается на последний запрос, который выполняется выше? Проблемы, если многие соединения выполняют запросы параллельно? – YvesR

+0

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

+0

Нужно ли делать sqlCon.Close(); '? Я думал, что «использование» должно сделать это за вас. – bluish

0

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

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; 
    } 
Смежные вопросы