Методы ExecuteNonQuery, ExecuteScalar и ExecuteReader объекта Command
Мы рассмотрели всю возможную функциональность, которую можно получить без использования каких-либо методов объекта Command. Для выполнения запросов на выборку простейших процедур достаточно просто указать тип и передать название запроса или процедуры. Все работает, но этого явно недостаточно для серьезных приложений. Поэтому забудем пока про хранимые процедуры, другие объекты ADO .NET, и сосредоточим все внимание на методах объекта Command.
Метод ExecuteNonQuery применяется для выполнения запросов, не возвращающих данные. Как же запросы, предназначенные именно для извлечения данных, могут не возвращать их? Речь идет о запросах типа UPDATE, INSERT и DELETE - в самом деле, они вносят изменения в таблицу базы данных, не возвращая ничего назад в результате выполнения. В самом языке SQL эти запросы образуют категорию DML (Data Manipulation Language, DML). Дословный перевод названия категории - "язык манипулирования данными", наличие слова "язык" вносит небольшую путаницу: в языке SQL есть язык DML. Но это именно так. После небольшого опыта подобные названия станут привычными.
Создайте новое консольное приложение и назовите его "Example ExecuteNonQuery". Привожу его полный листинг:
using System; using System.Data.SqlClient;
namespace ExampleExecuteNonQuery { class Class1 { [STAThread] static void Main(string[] args) { SqlConnection conn = new SqlConnection(); conn.ConnectionString = "integrated security=SSPI; data source=\".\"; persist security info=False; initial catalog=BDTur_firm2"; conn.Open(); SqlCommand myCommand = conn.CreateCommand(); myCommand.CommandText = "UPDATE Туристы SET Фамилия = 'Сергеева' WHERE Кодтуриста = 3"; myCommand.ExecuteNonQuery(); conn.Close(); } } }
Объект Command можно создавать, вызывая метод CreateCommand объекта Connection:
SqlCommand myCommand = conn.CreateCommand();
Ранее мы пользовались следующим способом:
SqlCommand myCommand = new SqlCommand(); myCommand.Connection = conn;
Эти два способа совершенно эквивалентны. В свойстве CommandText указывается непосредственно текст запроса, который устанавливает значение "Сергеева" поля "Фамилия" для записи с полем "Кодтуриста" = 3. Для выполнения запроса просто вызываем метод ExecuteNonQuery:
myCommand.ExecuteNonQuery();
Запускаем приложение, нажимая Ctrl+F5. При успешном выполнении запроса в консольном окне появляется надпись "Press any key to continue" (рис. 6.10):
Рис. 6.10. Выполнение приложения ExampleExecuteNonQuery
Запускаем SQL Server Enterprise Manager, открываем таблицу "Туристы" и убеждаемся в том, что запись изменилась (рис. 6.11).
Рис. 6.11. Таблица "Туристы", изменение записи
Метод ExecuteNonQuery все-таки что-то неявно возвращает - результат выполнения запроса в виде количества измененных записей; это может применяться для проверки (изменим фрагмент кода):
int UspeshnoeIzmenenie = myCommand.ExecuteNonQuery(); if (UspeshnoeIzmenenie !=0) { Console.WriteLine ("Изменения внесены"); } else { Console.WriteLine("Не удалось внести изменения"); }
Теперь, в зависимости от результата, будет появляться соответствующее сообщение (рис. 6.12).
Рис. 6.12. Результаты проверки выполнения запроса
Неудачный результат можно получить, установив в тексте запроса значения поля "Код туриста", равное, скажем, 10.
Закомментируем имеющееся свойство CommandText и добавим новое:
myCommand.CommandText = "INSERT INTO Туристы (Кодтуриста, Фамилия, Имя, Отчество) VALUES (6, 'Тихомиров', 'Андрей', 'Борисович')";
Запускаем приложение, переходим в SQL Server Enterprise Manager - запрос добавил новую запись (рис. 6.13):
Рис. 6.13. Таблица "Туристы", добавление записи
Снова закомментируем свойство CommandText, добавим теперь запрос на удаление записи:
myCommand.CommandText = "DELETE FROM Туристы WHERE Кодтуриста = 4";
Запускаем приложение - из таблицы удалена четвертая запись (рис. 6.14):
Рис. 6.14. Таблица "Туристы", удаление записи
Метод ExecuteNonQuery применяется также для выполнения запросов, относящихся к категории DDL языка SQL. Язык определения данных3) (Data Definition Language, DDL) позволяет создавать и изменять структуру объектов базы данных, например, создавать и удалять таблицы. Основными операторами этого языка являются CREATE, ALTER, DROP. В результате выполнения запросов DDL не возвращаются данные - именно поэтому мы можем применять метод ExecuteNonQuery. Закомментируем имеющееся свойство CommandText и напишем новое, создающее в базе "BDTur_firm2" новую таблицу "Отзывы":
myCommand.CommandText = "CREATE TABLE Отзывы (Кодотзыва INT NOT NULL, Кодтуриста INT NOT NULL, Комментарий VARCHAR(50)";
Запускаем приложение, затем переходим в SQL Server Enterprise Manager, нажимаем кнопку (обновить) на панели инструментов - в базе появляется новая таблица (рис. 6.15):
Рис. 6.15. База данных BDTur_firm2, новая таблица "Отзывы"
Для добавления нового столбца "Отзывтуриста" строка Command Text должна иметь следующий вид:
myCommand.CommandText = "ALTER TABLE Отзывы ADD Отзывтуриста VARCHAR(50)";
В SQL Server Enterprise Manager дважды щелкаем по названию таблицы - в появившемся окне "Table Properties" видим новое поле "Отзывтуриста" (рис. 6.16):
Рис. 6.16. Свойства таблицы "Отзывы"
Для удаления таблицы "Отзывы" запускаем приложение, содержащее следующую строку CommandText:
myCommand.CommandText = "DROP TABLE Отзывы";
Переходим в SQL Server Enterprise Manager - таблица полностью исчезла из базы данных. Если бы нам нужно было лишь удалить данные из таблицы, сохранив структуру, мы бы воспользовались следующей командой:
myCommand.CommandText = "DELETE FROM Отзывы";
Объектами базы данных могут быть не только таблицы, но и хранимые процедуры, схемы, представления.
В любом случае манипуляция с ними будет относиться к категории DDL.
Метод ExecuteNonQuery применяется для выполнения запросов, относящихся к категории DCL. Язык управления данными (Data Control Language, DCL) предназначен для управления доступом (определения полномочий) к объектам базы данных. Основными операторами этого языка являются GRANT, DENY, REVOKE. Мы не будем рассматривать выполнение этих запросов - использование в данном случае объекта Commnad не отличается ничем от рассмотренного выше.
В программном обеспечении к курсу вы найдете приложение Example ExecuteNonQuery (Code\Glava3\ ExampleExecuteNonQuery).
Метод ExecuteScalar объекта Command применяется для запросов, возвращающих одно значение. Мы сталкивались с такими запросами, когда использовали агрегатные функции COUNT, MIN, MAX. Создайте новое консольное приложение и назовите его "ExampleExecuteScalar". Полный листинг этого приложения:
using System; using System.Data.SqlClient;
namespace ExampleExecuteScalar { class Class1 { [STAThread] static void Main(string[] args) { SqlConnection conn = new SqlConnection(); conn.ConnectionString = "integrated security=SSPI;data source=\".\"; persist security info=False; initial catalog=BDTur_firm2"; conn.Open(); SqlCommand myCommand = conn.CreateCommand(); // SqlCommand myCommand = new SqlCommand(); // myCommand.Connection = conn; myCommand.CommandText = "SELECT COUNT (*) FROM Туры"; string KolichestvoTurov = Convert.ToString(myCommand.ExecuteScalar()); conn.Close(); Console.WriteLine("Количество туров: " + KolichestvoTurov); } } }
Возвращаемый методом ExecuteScalar результат мы привели к типу string для вывода в окно консоли. Запускаем приложение - как и следовало ожидать, запрос вернул число 5 (рис. 6.17):
Рис. 6.17. Приложение ExampleExecuteScalar, вывод количества туров
Можно несколько раз применять этот метод:
... myCommand.CommandText = "SELECT COUNT (*) FROM Туры"; string KolichestvoTurov = Convert.ToString(myCommand.ExecuteScalar()); myCommand.CommandText = "SELECT MAX (Цена) FROM Туры"; string MaxPrice = Convert.ToString(myCommand.ExecuteScalar()); myCommand.CommandText = "SELECT MIN (Цена) FROM Туры"; string MinPrice = Convert.ToString(myCommand.ExecuteScalar()); myCommand.CommandText = "SELECT AVG (Цена) FROM Туры"; string AvgPrice = Convert.ToString(myCommand.ExecuteScalar()); conn.Close(); Console.WriteLine("Количество туров: " + KolichestvoTurov + "\nСамый дорогой тур, цена в руб. : " + MaxPrice + "\nСамый дешевый тур, цена в руб.: " + MinPrice + "\nСредняя цена туров: " + AvgPrice); }
Запускаем приложение4) - получаем несколько значений из базы данных (рис. 6.18):
Рис. 6.18. Приложение ExampleExecuteScalar, вывод нескольких значений
Когда требуется получать подобные одиночные значения, всегда следует применять метод ExecuteScalar - это позволяет значительно повысить производительность.
В программном обеспечении к курсу вы найдете приложение Example ExecuteScalar (Code\Glava3\ ExampleExecuteScalar).
Мы переходим к рассмотрению очень важного метода - ExecuteReader. Он применяется для получения набора записей из базы данных. Особенностью этого метода является то, что он возвращает специальный объект DataReader, с помощью которого просматриваются записи. Для хранения данных, полученных из базы, мы до этого использовали объект DataSet. Объект DataReader, в отличие от DataSet, требует наличия постоянного подключения для извлечения и просмотра данных, кроме того, он открывает данные только для чтения. Создайте новое консольное приложение и назовите его "ExampleExecuteReader". Полный листинг этого приложения:
using System; using System.Data.SqlClient;
namespace ExampleExecuteReader { class Class1 { [STAThread] static void Main(string[] args) { SqlConnection conn = new SqlConnection(); conn.ConnectionString = "integrated security=SSPI;data source=\".\"; persist security info=False; initial catalog=BDTur_firm2"; SqlCommand myCommand = conn.CreateCommand(); //SqlCommand myCommand = new SqlCommand(); //myCommand.Connection = conn; myCommand.CommandText = "SELECT * FROM Туристы"; conn.Open(); SqlDataReader dataReader = myCommand.ExecuteReader();
while (dataReader.Read()) { Console.WriteLine(dataReader["Фамилия"]); } dataReader.Close(); conn.Close(); } } }
Объект dataReader создается в результате вызова метода Execute Reader объекта myCommand:
SqlDataReader dataReader = myCommand.ExecuteReader();
Перед считыванием первой записи вызываем метод Read объекта dataReader и выводим набор записей в консольное окно.
Запускаем приложение5) (рис. 6.19).
Рис. 6.19. Приложение "ExampleExecuteReader". Вывод поля "Фамилия"
Объект DataReader возвращает набор данных типа object, причем для обращения можно использовать индекс:
Console.WriteLine(dataReader[1]);
Это совершенно эквивалентная строка вывода6).
Перечислим несколько полей:
... Console.WriteLine(dataReader[0]); Console.WriteLine(dataReader[1]); Console.WriteLine(dataReader[2]); Console.WriteLine(dataReader[3]); ...
При выводе они будут располагаться в структурированном виде (рис. 6.20):
Рис. 6.20. Приложение ExampleExecuteReader, вывод содержимого всех полей
Поскольку мы имеем дело с объектами (тип данных object), для вывода записей в виде строк неприменимо их простое объединение:
... Console.WriteLine(dataReader[0] + dataReader[1] + dataReader[2] + dataReader[3]); ...
Преобразованные к типу string значения можно объединять:
Console.WriteLine(Convert.ToString(dataReader[0]) + " "+ Convert.ToString(dataReader[1]) + " "+Convert.ToString(dataReader[2]) + " "+ Convert.ToString(dataReader[3]));
Теперь записи выводятся в более привычном виде (рис. 6.21):
Рис. 6.21. Приложение ExampleExecuteReader. Вывод содержимого всех полей в виде записей
В программном обеспечении к курсу вы найдете приложение "Example ExecuteReader" (Code\Glava3\ ExampleExecuteReader).