Исполнить команду, возвращающую набор, с помощью объекта Command можно методом ExecuteReader(). Он возвращает объект DataReader.
Объект DataReader – это упрощенный объект, обеспечивающий быстрое и эффективное последовательное однонаправленное чтение данных. Он позволяет перебирать записи результирующего набора, передавая нужные значения напрямую коду приложения. При этом данные разрешается просматривать только в одном направлении (нельзя вернуться к записи, прочитанной ранее). Кроме того, объект DataReader ориентирован на использование постоянных соединений и, пока он существует, требует монопольного доступа к активному соединению.
Объект DataReader нельзя создать напрямую, это делается путем вызова метода ExecuteReader объекта Command. Подобно другим членам классов провайдеров данных у каждого класса DataProvider есть собственный класс DataReader. Например, объект SqlCommand возвращает SqlDataReader.
При вызове метода ExecuteReader объект Command исполняет представленную им команду и создает объект DataReader соответствующего типа, который можно записать в переменную ссылочного типа.
Получив ссылку на объект DataReader, можно просматривать записи, загружая нужные данные в память. У нового объекта DataReader указатель чтения устанавливается на первую запись результирующего набора. Чтобы сделать ее доступной, следует вызвать метод Read. Если запись доступна, метод Read переводит указатель объекта DataReader к следующей записи и возвращает true, в противном случае метод Read возвращает false. Таким образом, метод Read используют для перебора записей в цикле while, например, так:
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
…
}
Для перебора записей также можно использовать цикл foreach. Класс SqlDataReader содержит метод GetEnumerator, и при каждом шаге цикла он будет возвращать объект DbDataRecord, представляющий одну запись, который можно сохранить, например, в ArrayList.
Выполнение метода ExecuteReader() требует открытого соединения с базой данных. Закончив чтение данных, вызовите метод Сlose() объекта DataReader, чтобы закрыть соединение.
При чтении записи с помощью объекта DataReader значения отдельных полей доступны через индексатор или свойство по умолчанию в виде массива объектов, к элементам которого разрешается обращаться но индексу:
Object о = rdr[3];
или по имени поля:
object о = rdr["CustomerID"];
При этом способе доступа DataReader предоставляет все значения в виде объектов, хотя из DataReader можно извлекать и типизированные данные. Более подробно об этом рассказано далее.
Прочитав данные с помощью DataReader, следует вызвать метод Сlose(), чтобы закрыть DataReader, иначе объект DataReader будет удерживать монопольный доступ к активному соединению, сделав его недоступным другим объектам. При вызове метода ExecuteReader(), установив свойство CommandBehavior в CloseConnection, вы автоматически закроете соединение, не вызывая метод Close() явно.
Работа с автономными данными в ADO.NET
Работа с данными в автономном режиме – более эффективное решение при создании многопользовательских распределенных систем. Следовательно, необходим объект для хранения автономных данных. Этот объект играет роль универсального посредника. Поэтому для объекта, хранящего автономные данные не должно быть разницы, является источником данных Microsoft SQL Server или Oracle. Таким универсальным посредником является объект DataAdapter.
Объект DataAdapter
Объекты DataAdapter обеспечивают связь между источником данных и объектом DataSet (или DataTable), управляя обменом данных и контролируя их передачу. Одни приложения осуществляют одностороннюю передачу данных, а другим требуется не только извлекать, но и модифицировать данные источника. Объект DataAdapter способен извлекать данные, заполнять объекты DataSet или DataTable и при необходимости обновлять содержимое источника данных. Конкретная реализация адаптера данных зависит от типа источника данных. Для работы с базами данных SQL Server используется специализированный класс SqlDataAdapter, а для работы с базами данных Oracle – класс OracleDataAdapter.
Класс SqlDataAdapter имеет четыре свойства для работы c источником данных:
SelectCommand – содержит текст или объект команды, осуществляющей выборку данных из базы данных; при вызове метода Fill() эта команда исполняется и заполняет объект DataTable или объект DataSet;
DeleteCommand – содержит текст или объект команды, осуществляющий удаление строки из таблицы;
UpdateCommand – содержит текст или объект команды, осуществляющий обновление значений в базе данных.
Чтобы заполнить DataTable данными, следует вызвать метод Fill() объекта DataAdapter. Этот метод исполняет команды, заданные свойством SelectCommand, на соединении, указанном свойством Connection, и заполняет DataSet данными, которые возвращает исполненная команда. Методу Fill() необходимо передать целевой объект, которым может быть DataTable:
DataTable dt = new DataTable();
myDataAdapter. Fill (dt);
Взаимодействия с объектом Connection не происходит. При исполнении команды, вызванной методом Fill(), соединение открывается только на время извлечения данных, после чего сразу же закрывается. Таким образом, после извлечения данные становятся отсоединенными и ими можно манипулировать в коде независимо от базы данных, а при необходимости ее можно обновить.
Мы изучили работу с автономными данными и использование строго типизированного объекта DataSet. Одно из главных различий между компонентом чтения данных DataReader, описанным в прошлой главе, и объекта DataSet заключается в том, что DataReader потребляет меньше памяти, чем DataSet. В зависимости от объема данных и доступной памяти, разница в производительности вследствие более экономного использования памяти может быть огромной.
Однако при решении вопроса о том, должно ли приложение использовать DataReader или объект DataSet, следует внимательно проанализировать функциональность, которая необходима для разрабатываемого приложения. Объект DataSet предназначен для эффективного выполнения следующих задач:
локальное кэширование данных в приложении для последующей обработки. Если нужно только считывать результаты запроса, класс DataReader подходит наилучшим образом;
удаленное взаимодействие с данными между уровнями или от веб-службы ХМL;
динамическое взаимодействие с данными, например привязка к элементу ynpавления Windows Forms или комбинирование и связывание данных из-нескольких источников;
выполнение интенсивной обработки, не требующей открытого соединения с источником данных, что освобождает соединение для использования другими клиентами.
Если широкая функциональность, которую предоставляет типизированный объект DataSet, не нужна для работы приложения, можно повысить его производительность, используя объект DataReader для возврата данных. Хотя класс DataAdapter использует класс DataReader для заполнения содержимого DataSet, путем применения объекта DataReader можно повысить производительность приложения, т. к. будет экономиться память, которую потреблял бы объект DataSet, и избежать обработки, необходимой для создания и заполнения содержимого DataSet.
Существуют более современные технологии доступа к данным, использование которых при создании приложений для работы с данными более эффективно, чем применение строго типизированных DataSet.