Статья
Версия для печати
Обсудить на форуме
Command - средство для работы с командами SQL


О примерах к данной статье

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

Поскольку в установленном мною недавно Microsoft Office 2003 почему-то не оказалось базы данных Борей, которую я использовал до сих пор для примеров, с этого момента и далее я буду использовать с этой целью аналогичную базу NorthWind, которую я обнаружил в составе Visual Studio 6.

Для выполнения примеров вам придется выполнить некоторые подготовительные действия: открыть проект (или создать новый) на языке C#, создать соединение с базой данных NorthWind и задать ему имя cnnNwind.

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

Соглашения о терминах

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

Так, например, при чтении вы неоднократно встретите выражения вроде объект Command. Разумеется, речь идет при этом отнюдь не об объекте с точно таким именем.

Во-первых, очевидно, что речь при этом идет об экземпляре объекта, относящегося к данному классу.

Во-вторых, как вы уже знаете из предыдущих статей, реализации многих классов ADO.NET различаются в зависимости от используемого программой Провайдера Данных. Так, например, не существует класса Command в чистом виде. Вместо него следует использовать для Провайдера OLE DB - OleDbCommand, для Провайдера MS SQL Server - соответственно SqlCommand.

Тем не менее, реализации этих классов весьма сходны, а отличия в деталях я по возможности оговариваю отдельно. Таким образом, если речь идет об объекте Command, не забывайте, что на самом деле имеются в виду общие черты экземпляров классов OleDbCommand и SqlCommand. Впрочем, сомневаюсь, что столь строгое следование терминологии сделало бы статью легче читаемой.

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

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

Назначение объекта Command

Объект ADO.NET Command предназначен для инкапсуляции команды SQL или хранимой процедуры.

Примечание. Хотя предполагается, что читатель уже имеет некоторое представление о реляционных базах данных, все же для новичков скажу несколько слов о возможно новых для них понятиях.
SQL (Structured Query Language, Структурированный Язык Запросов) - стандарт де-факто среди языков для работы с реляционными базами данных, некогда многочисленных. Операторы SQL можно разделить на два подмножества - DDL (Data Definition Language, язык определения данных, ЯОД), предназначенный для описания структуры базы данных и входящих в нее объектов, и DML (Data Manipulation Language, язык манипулирования данными, ЯМД), предназначенный, как видно из названия, для манипуляции содержимым базы данных.
Совокупность операторов SQL, выполняющую логически целостное действие над базой данных, будем называть командой SQL.
Хранимой процедурой называется именованная последовательность операторов SQL, которая расположена на сервере баз данных (в широком смысле этого слова, включая невыделенные источники данных наподобие MS SQL Server Desktop Edition или Microsoft Jet). Подобно процедурам в традиционных языках программирования, хранимая процедура может быть вызвана по имени, принимать входные и/или выходные параметры, возвращать результирующее значение, а также иметь побочные действия.


Это довольно универсальное средство для работы с данными: помимо чтения и изменения данных, Command может выполнять запросы, не возвращающие результатов, а также выполнять команды DDL, которые могут изменить структуру источника данных.

Если Command в результате выполнения возвращает данные, доступ к ним может быть получен посредством объекта DataReader. Фактически он представляет собой поток данных только на чтение, который можно однократно просматривать, продвигаясь только вперед.

DataReader получает данные от источника построчно. Вследствие этого он занимает весьма мало ресурсов компьютера, только лишь на хранение в оперативной памяти одной строки. При этом метод Read используется для получения очередной строки от источника, а GetType (где Type - один из системных типов данных) служит для доступа к значениям столбцов.

Поскольку Command и DataReader являются частью Провайдера Данных (см. соответствующую диаграмму во вводной статье), то они специфичны для каждого из источников данных. Для System.Data.OleDb это соответственно OleDbCommand и OleDbDataReader, для System.Data.SqlClient - SqlCommand и SqlDataReader (подробнее см. выше раздел Соглашение о терминах).

Примечание. Поскольку объекты Command и DataReader весьма тесно связаны, первоначально я планировал рассмотреть их в одной статьи. Но видя, что объем материала, подлежащего рассмотрению по объекту Command, и так уже превзошел все мои ожидания, а вместе с ним и время работы над статьей превысило мыслимые сроки, я решил рассмотреть объект DataReader в отдельной статье. Здесь же он будет упомянут по минимуму, лишь настолько, сколь это необходимо для понимания его взаимосвязи с Command.

Создание объекта Command

Command может быть создан и сконфигурирован как на этапе разработки программы при помощи инструментальных средств Visual Studio, так и на этапе выполнения - программно. В отличие от него DataReader может быть создан только на этапе выполнения при помощи метода ExecuteReader объекта Command.

Создание Command средствами Visual Studio

Во время разработки программы можно создать объект Command перетаскиванием его пиктограммы с панели инструментов на форму. Поскольку Command не имеет визуального интерфейса, то он появляется под формой, на панели Component Designer.

Примечание. Напоминаю, что для выполнения примеров к данной статье необходимо выполнить ряд подготовительных действий. Если вы этого еще не сделали, вернитесь к разделу О примерах к данной статье в самом начале стетьи.
  • На панели инструментов открываем вкладку Data.
  • Перетаскиваем мышью значок OleDbCommand на форму.
  • При необходимости меняем имя созданного объекта на более подходящее в окне Properties.

Вновь созданный объект появляется на панели Component Designer:



Создание Command во время выполнения программы

Можно создать объект Command и непосредственно во время выполнения программы, как и любой другой объект.

Command имеет 4 версии конструктора:

new ()создает новый Command
new (string cmd)То же + задан текст запроса cmd
new (string cmd, Connection cnn)То же + задано соединение с источником данных cnn
new (string cmd, Connection cnn, Transaction trn)То же + задана транзакция trn, в которой выполняется запрос

Пример программного создания Command:
Код:
public System.Data.OleDb.OleDbCommand cmd;

cmd = new System.Data.OleDb.OleDbCommand;

Свойства объекта Command

Краткая сводка свойств:

СвойствоТипНазначение
CommandTextstringОператор SQL или имя хранимой процедуры
СommandTimeoutintВремя (в секундах), в течение которого ожидается ответ источника данных
CommandTypeCommandTypeУказывает, как интерпретируется commandText; по умолчанию Text.
ConnectionConnection*Соединение с источником данных, по которому выполняется команда
ParametersParameterCollection*Коллекция параметров команды
TransactionTransaction*Транзакция, в среде которой выполняется команда
UpdatedRowSourceUpdateRowSourceОпределяет, каким образом результаты выполнения команды применяются к DataRow, когда команда используется методом Update объекта DataAdapter*.

Примечание. Типы данных, помеченные знаком *, являются обобщенными и должны быть конкретизированы для данного Провайдера. Например, при использовании провайдера OLE DB .NET следует Connection заменить на OleDbConnection.

CommandText - это текстовая строка, которая содержит либо текст команды на языке SQL, либо имя хранимой процедуры, которую необходимо вызвать.

Если вы намерены использовать команду SQL или хранимую процедуру с параметрами, следует учитывать, что разные Провайдеры используют различный синтаксис для передачи параметров (подробнее см. далее в разделе Использование коллекции Parameters).

CommandTimeout - время в секундах, в течение которого Command ожидает ответа сервера, прежде чем сгенерировать ошибку. Имейте в виду, что этот параметр задает максимальное время ожидания начала поступления данных, а не полного выполнения команды. Например, если таблица велика, а соединение медленное, может потребоваться несколько десятков минут на загрузку всех данных. Но если первая строка пришла в положенное время, ошибка сгенерирована не будет.

Если CommandTimeout имеет значение 0, это означает, что время ожидания выполнения программы не ограничено. Следует избегать нулевого значения, поскольку в этом случае программа может просто зависнуть на неопределенный срок.

CommandType - задает, каким образом интерпретируется содержимое свойства CommandText. Допустимые значения:

StoredProcedureИмя хранимой процедуры
TableDirectИмя таблицы, все строки и столбцы которой будут возвращены как результат выполнения команды; поддерживается только Провайдером OLE DB.
TextТекст команды на языке SQL (значение по умолчанию)

Connection - ссылка на объект Connection, используемый для выполнения команды. Разумеется, этот объект должен принадлежать тому же пространству имен, что и Command.

Недопустимо изменять значения свойств Connection, CommandType и CommandText во время выполнения транзакции. В этом случае генерируется исключение InvalidOperationException.

Parameters - содержит коллекцию параметров для команды SQL или хранимой процедуры.

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

UpdatedRowSource - Определяет, каким образом результаты выполнения команды применяются к DataRow, когда команда используется методом Update объекта DataAdapter (будет рассмотрен в последующих статьях, здесь упомянут лишь для полноты изложения). Допустимые значения:

BothИ выходные параметры, и первая строка, возвращаемая Command, отображаются на изменяемую строку
FirstReturnedRecordПервая строка, возвращаемая Command, отображаются на изменяемую строку
NoneВсе возвращаемые командой данные игнорируются
OutputParametersВыходные параметры, возвращаемые Command, отображаются на изменяемую строку
Если объект Command сгенерирован средствами Visual Studio, то свойство UpdatedRowSource устанавливается в None, если же объект создан во время выполнения программы, то в Both.

Поскольку свойство UpdatedRowSource тесно связано с объектом DataRow, более подробно мы его рассмотрим в соответствующей статье.

Установка свойств Command во время разработки

Как и для других компонентов, допускающих настройку на этапе разработки, свойства объекта Command могут быть установлены в окне Properties:



  • В окне Form Designer выбираем созданный нами ранее объект Command.
  • В окне Properties меняем свойство Name на cmdGetEmployees.
  • Устанавливаем свойство Connection на Existing  cnnNwind.
  • Выбираем свойство CommandText и жмем кнопку . Появляется окно AddTable:

  • Выбираем строку Employees, затем жмем Add, Close.
  • Устанавливаем CheckBox * (All Column) в окне Query Builder:

    Обратите внимание на то, что среда разработки автоматически сгенерировала запрос на языке SQL, который выбирает все данные из таблицы Employees.
  • Нажимаем OK.
Просмотрев код сгенерированный Visual Studio, мы можем найти строки, относящиеся к инициализации объекта Command:
Код:
//
// cmdGetEmployees
//
this.cmdGetEmployees.CommandText = "SELECT Employees.* FROM Employees";
this.cmdGetEmployees.Connection = this.cnnNwind;

Установка свойств Command во время выполнения

Большинство свойств объекта Command можно задать на этапе выполнения программы обычным оператором присваивания. Исключение составляет свойство Parameters, которое представляет собой коллекцию. Параметры команды добавляются к коллекции вызовом метода Add.
Код:
//
// cmdGetCustomers
//
this.cmdGetCustomers.CommandText = "SELECT Employees.* FROM Employees";
this.cmdGetCustomers.CommandType = CommandType.Text;
this.cmdGetEmployees.Connection = this.cnnNwind;

Использование коллекции Parameters

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

  • задать параметры в запросе или хранимой процедуре;
  • добавить параметры в коллекцию Parameters;
  • задать значения параметров.
К сожалению, в данный момент не существует единого синтаксиса для задания параметров. Так, при использовании хранимых процедур синтаксис определяется источником данных, на котором создана хранимая процедура. Если же параметры используются в запросе SQL, заданном свойством CommandText объекта Command, в этом случае синтаксис определяется Провайдером Данных .NET.

Так, например, .NET Framework Data Provider for SQL Server требует, чтобы параметры были именованными с префиксом @:
Код:
SELECT * FROM Customers WHERE (CustomerID = @CustID)

.NET Framework Data Provider for OLE DB и .NET Framework Data Provider for ODBC используют несколько иной синтаксис. Параметры в этом случае обозначаются вопросительным знаком ?:
Код:
SELECT * FROM Customers WHERE (CustomerID = ?)

В этом случае, если команда SQL или хранимая процедура имеют несколько параметров, их порядок в коллекции Parameters должен быть согласован с порядком параметров в CommandText или хранимой процедуре.

После создания хранимой процедуры или параметризованного запроса SQL (п. 1) следует добавить параметры в коллекцию Parameters объекта Command (п. 2). Если вы используете средства Visual Studio .NET, она создаст параметры автоматически. если же объект Command создается или изменяется во время выполнения программы, следует использовать метод Add коллекции Parameters для каждого из параметров. При этом не следует забывать, что для неименованных параметров порядок их добавления имеет большое значение.

Коллекция Parameters предоставляет несколько методов для задания параметров во время выполнения:

Add(Value)Добавляет параметр со значением Value
Add(Parameter)Добавляет Parameter
Add(Name, Value)Добавляет параметр с именем Name и значением Value
Add(Name, Type)Добавляет параметр с именем Name и типом Type
Add(Name, Type, Size)Добавляет параметр с именем Name, типом Type и размером Size
Add(Name, Type, Size, SourceColumn)Добавляет параметр с именем Name, типом Type, размером Size и отображает его на колонку DataTable, заданную строкой SourceColumn
ClearУдаляет все параметры из коллекции
Insert(Index, Value)Вставляет параметр с заданным значением в позицию, заданную Index (начиная с 0)
Remove(Value)Удаляет параметр с заданным значением Value
RemoveAt(Index)Удаляет параметр в позиции, заданной Index (начиная с 0)
RemoveAt(Name)Удаляет параметр с заданным именем Name
Объект Parameter

Реализации параметров для провайдеров OLE DB (OleDbParameter) и MS SQL (SqlParameter) весьма сходны, как видно из приведенных ниже описаний.

Свойства объекта Parameter

Перечень основных свойств Parameter приведен в таблице:

СвойствоТипНазначениеOLE DBSQL
DbTypeDbTypeТип данных параметра++
DirectionParameterDirectionНаправление передачи данных++
IsNullableboolМожет принимать значение null++
OffsetintСм. ниже-+
OleDbType OleDbTypeТип данных OLE DB+-
ParameterNamestringИмя параметра++
PrecisionbyteМаксимальное кол-во цифр для представления значения свойства Value++
ScalebyteКол-во цифр в дробной части Value++
SizeintМаксимальный размер данных в байтах++
SourceColumnstringИмя столбца Dataset, который получает или возвращает значение Value++
SourceVersionDataRowVersionСм. ниже++
SqlDbTypeSqlDbTypeТип данных SQL-+
ValueobjectЗначение параметра++
Все перечисленные свойства доступны как на чтение, так и на запись.

Свойство DbType (по умолчанию string) задает тип данных параметра, который может принимать одно из приведенных ниже значений:

AnsiString Последовательность non-Unicode символов переменной длины в диапазоне от 1 до 8,000.
AnsiStringFixedLength Последовательность non-Unicode символов фиксированной длины.
Binary Последовательность двоичных данных переменной длины в диапазоне от 1 до 8,000 байт.
Примечание.ADO.NET некорректно работает с двоичными массивами размером более 8,000 байт.
Boolean Значения типа Boolean: true или false.
Byte 8-битное беззнаковое целое в диапазоне от 0 до 255.
Currency .Значение currency в диапазоне от -263 (or -922,337,203,685,477.5808) до 2 63 -1 (or +922,337,203,685,477.5807) с точностью 1/10.000 валютной единицы.
DateДата и время в диапазоне от 1 января 1753 г. до 31 декабря 9999 г. с точностью 3.33 миллисекунды.
DateTimeТип, представляющий значения даты и времени.
Decimal Представление величин в диапазоне от 1.0 x 10-28 до приблизительно 7.9 x 10 28 с 28-29 значащими цифрами.
Double .Тип с плавающей точкой для представления величин в диапазоне от 5.0 x 10-324 до 1.7 x 10 308 с точностью 15-16 цифр.
Guid A globally unique identifier (GUID).
Int16 Целочисленный тип для представления 16-битных знаковых чисел в диапазоне от -32768 до 32767.
Int32 Целочисленный тип для представления 32-битных знаковых чисел в диапазоне от -2147483648 до 2147483647.
Int64Целочисленный тип для представления 64-битных знаковых чисел в диапазоне от -9223372036854775808 до 9223372036854775807.
ObjectОбщий тип для представления любого ссылочного типа или значения, для которого нет другого явного представления в DbType.
SByteЦелочисленный тип для представления 8-битных знаковых чисел в диапазоне от -128 до127.
SingleТип с плавающей точкой для представления величин в диапазоне от 1.5 x 10-45 до 3.4 x 10 38 с точностью 7 цифр.
StringСтрока символов Unicode.
StringFixedLengthСтрока символов Unicode фиксированной длины.
TimeДата и время в диапазоне от 1 января 1753 г. до 31 декабря 9999 г. с точностью 3.33 миллисекунды
UInt16Целочисленный тип для представления 16-битных беззнаковых чисел в диапазоне от 0 до 65535.
UInt32Целочисленный тип для представления 32-битных беззнаковых чисел в диапазоне от 0 до 4294967295.
UInt64Целочисленный тип для представления 64-битных беззнаковых чисел в диапазоне от 0 до 18446744073709551615.
VarNumeric Числовое значение переменной длины.
Свойство DbType связано со свойствами OleDbType или SqlDbType в зависимости от Провайдера Данных, так что изменение его значения автоматически влечет изменение значения связанного свойства.

Свойство Direction задает направление передачи данных параметра:

InputВходной параметр.
InputOutputПараметр является входным и выходным.
OutputВыходной параметр.
ReturnValue Значение, возвращаемое хранимой процедурой, встроенной или пользовательской функцией.
Свойство IsNullable задает, может ли данный параметр принимать значение null. (Для задания самого значения null следует использовать свойство Value объекта DBNull).

Свойство Offset используется для работы с полями большого размера (двоичными либо строковыми), которые из-за своего размера не могут быть обработаны за одну операцию чтения/записи. В случае, если планируется считывание либо запись такого поля порциями по N байт, необходимо в каждой итерации смещать значение Offset на N.

Свойства OleDbType и SqlDbType, как уже упоминалось выше, связаны со свойством DbType. Фактически эти пары свойств задают отображение логического типа данных DbType на физический, зависящий от реализации Провайдера данных. Я не буду здесь перечислять возможные значения этого свойства из-за их громоздкости, эту информацию вы без труда найдете в MSDN.

Свойство ParameterName, как нетрудно догадаться, задает имя параметра, по которому к нему можно обращаться через коллекцию Parameters. При этом не следует забывать, что Провайдер OLE DB не использует именованные параметры, поэтому задание имен параметров в этом случае допустимо, но большого смысла не имеет.

Свойство Precision используется только для числовых входных параметров. Оно задает количество десятичных цифр, используемых для представления результата. Значение по умолчанию 0, это означает, что Провайдер выбирает точность представления самостоятельно. В случае, если указано слишком маленькое количество цифр, чтобы вместить данное число, поведение программы зависит от реализации Провайдера: он может либо выдать исключение, либо отбросить не вместившиеся цифры.

Свойство Scale также используется только для числовых входных параметров. Оно задает количество цифр для представления дробной части числа.

Свойство Size используется для двоичных и строковых данных, оно ограничивает максимальный размер данных, которые могут быть записаны/считаны из базы данных. Для двоичных данных и строк ANSI оно задает размер данных в байтах, в случае строк Unicode - в символах. Значение этого свойства необходимо задавать для выходных и двунаправленных параметров. Если значение для входного параметра не задано явно, оно будет вычислено автоматически исходя из фактического значения параметра. Для типов фиксированного размера значение данного свойства игнорируется.

Свойство SourceVersion используется при обновлениях данных для того, чтобы задать, использовать ли первоначальное или обновленное значение для данного параметра. Это позволяет изменять первичные ключи.

Наконец, самое важное свойство Value - не что иное, как фактическое значение параметра. При его использовании следует иметь в виду, что для передачи в базу данных пустого значения (NULL) следует задавать данному свойству значение DBNull, а не null.

Конфигурирование параметров в среде Visual Studio.NET


Конфигурирование параметров средствами Query Builder

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

  • Создаем новую команду cmdGetCustomers аналогично тому, как ранее создали cmdGetEmployees. Задаем значение свойства Connection равным cnnNwind.
  • Выбираем свойство CommandText и нажимаем кнопку . Открывается уже знакомый нам QueryBuilder с окном Add Table.
  • На закладке Tables выбираем таблицу Customers и жмем кнопку Add. На панели Query Builder появляется таблица Customers:

  • На пиктограмме таблицы Customers в верхней части Query Builder выбираем * (All Columns) и Country.
  • В таблице под пиктограммой в строке, содержащей Country в столбце Column, в графе Output снимаем выделение, в графе Criteria вводим символ ?. Query Builder автоматически строит запрос на SQL, который отображается под таблицей. Разумеется, этот запрос можно было бы ввести и вручную, но такой способ зачастую позволяет сформировать запрос быстрее, а новичков в SQL еще и избавляет от ошибок при наборе:

  • Установив опцию Regenerate parameters collection for this command, нажимаем кнопку OK. (Этим действием мы сообщаем среде разработки, что требуется внести изменения в коллекцию параметров данной команды, приведя их в соответствие с текстом запроса. При желании эту работу можно выполнить и вручную, если у вас есть на то веские причины. В данный момент я их не вижу, поэтому перекладываю ее на Visual Studio),
  • Появляется окно с предупреждением:

    Выбираем Да.
  • Теперь мы можем проверить работоспособность нашей команды с параметрами. Жмем правой кнопкой мыши где-нибудь в окне Query Builder и из контекстного меню выбираем опцию Run. Поскольку наша команда параметризована, для ее выполнения необходимо задать значение параметра. Для этого Query Builder выводит специальную таблицу:

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


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


Конфигурирование параметров при помощи Редактора параметров.

Для настройки свойств параметров предназначен Редактор параметров.

  • На панели Дизайнера Форм выбираем cmdGetCustomers.
  • В окне свойств объекта выбираем Parameters и жмем кнопку . Появляется окно Редактора параметров:

  • Теперь можно добавлять новые параметры к коллекции и удалять существующие, а также менять их свойства: направление обмена данными, тип данных и т.п.

Добавление параметров команды во время выполнения программ
Код:
this.cmdGetCustomers.Parameters.Add("Country", OleDbType.VarWChar, 15, "Country");

Задание значений параметров

Задавать значения параметров можно только во время выполнения программы! Впрочем, это и неудивительно, поскольку команда, всегда вызываемая с одними и теми же параметрами, определенными еще на этапе разработки, может быть сформирована более простыми средствами без использования коллекции Parameters.

Задание значения параметра производится обычным присваиванием значения свойству параметра Value:
Код:
this.cmdGetCustomers.Parameters["Country"].Value = USA;

Методы объекта Command

Самые важные из методов объекта Command, пожалуй, те, которые имеют отношение непосредственно к выполнению команды.

ExecuteNonQuery используется в случае, когда команда SQL или хранимая процедура не возвращают результата. К таким операциям относятся, например, запрос структуры базы данных или создание различных объектов базы данных, таких как таблицы, хранимые процедуры или триггеры. Также не возвращают значений запросы, используемые для добавления, удаления или модификации данных.

Несмотря на то, что ExecuteNonQuery сам по себе не возвращает данных, тем не менее выходные параметры по-прежнему могут быть задействованы.

В случае запросов UPDATE, INSERT или DELETE метод возвращает количество строк, на которые повлиял данный запрос. В остальных случаях возвращается значение -1.

ExecuteScalar используется с командами SQL или хранимыми процедурами, возвращающими единственное значение (на самом деле фактически получено значений может быть гораздо больше, но метод вернет только первый столбец первой строки результирующего набора, остальные результаты будут утеряны). Данный метод целесообразно использовать для работы с агрегатными запросами, например, подсчетом строк в таблице.

ExecuteDataReader выполняет запрос, заданный посредством свойства CommandText, и возвращает результат в виде объекта DataReader. Объект DataReader сложен сам по себе, и его рассмотрению будет посвящена отдельная статья, поэтому здесь его рассматривать подробно не будем. Пока же остается только добавить, что этот метод имеет необязательный аргумент CommandBehaviour, принимающий по умолчанию значение 0. Этот аргумент представляет собой набор флагов, имеющих следующее назначение:

ИмяОписаниеЗначение
CloseConnectionПосле выполнения команды связанный с ней объект Connection закрывается при закрытии DataReader.32
DefaultЗапрос может возвращать несколько наборов данных, его выполнение может повлиять на состояние базы данных. Вызов ExecuteReader(CommandBehavior.Default) эквивалентен вызову ExecuteReader().0
KeyInfoЗапрос возвращает информацию о столбце и первичном ключе, он выполняется без блокировки выбранных строк.
Примечание.При использовании KeyInfo .NET Framework Data Provider for SQL Server добавляет к выполняемому оператору оборот FOR BROWSE. Поэтому нужно учитывать возможные побочные эффекты, например, взаимодействие с операторами SET FMTONLY ON.
4
SchemaOnlyЗапрос возвращает только информацию о столбцах и не влияет на состояние базы данных.2
SequentialAccessОбеспечивает DataReader возможность работы со строками, содержащими двоичные данные большого размера. Вместо загрузки строки целиком, SequentialAccess позволяет DataReader загружать данные как поток. Затем можно использовать методы GetBytes или GetChars для задания байта, с которого следует начать считывание, тем самым используя ограниченный объем буфера для считываемых данных
При использовании SequentialAccess необходимо считывать все данные из столбцов в том порядке, в котором они возвращаются, даже если вас не интересуют данные из некоторых столбцов. После того, как некоторые данные считаны из потока, они уже не могут быть повторно считаны из него.
16
SingleResultЗапрос возвращает единственный набор результатов.1
SingleRowЗапрос должен вернуть единственную строку. Его выполнение может изменить состояние базы данных. Провайдеры данных могут использовать этот факт для оптимизации выполнения команды.
Допустимо задание SingleRow при выполнении запросов, возвращающих несколько результирующих наборов данных. В этом случае по-прежнему будет возвращаться несколько наборов, но каждый из них будет содержать лишь одну строку.
8
ExecuteXmlReader используется только Провайдером для MS SQL. Поскольку работа с XML в среде ADO.NET - это тема отдельного разговора, сейчас этот метод рассматривать не будем.

Кроме перечисленных, объект Command имеет также ряд вспомогательных методов.

Cancel пытается остановить выполнение команды. Если остановить выполнение не удается, к ошибке выполнения это тем не менее не приводит.

CreateParameter создает новый экземпляр параметра.

Prepare пытается создать откомпилированную версию команды на источнике данных. Разумеется, если CommandType = TableDirect, этот метод ничего не делает. В случае, если CommandType = StoredProcedure, этот метод может оптимизировать выполнение процедуры (хотя это и не гарантируется, поскольку в первую очередь определяется возможностями источника данных). Значения всех параметров должны быть заданы до вызова Prepare.

ResetCommandTimeout устанавливает свойство Timeout в значение по умолчанию.

Заключение

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

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

Alf, 25/07/2004

Версия для печати
Обсудить на форуме