При определении объектов ADO .NET мы назвали DataAdapter адаптером, преобразователем, предназначенным для взаимодействия с базой данных. Это действительно так, однако если рассматривать взаимодействие с базой данных более глубоко, то выясняется, что в ADO .NET есть специализированный объект для выполнения запросов, называемый Command. Под запросами понимается выполнение SQL-конструкций или запуск хранимых процедур. С объектом Command мы познакомились еще во второй лекции, но у вас могло сложиться впечатление, что его введение достаточно формально - вполне можно обойтись одним объектом DataAdapter. Например, в приложении VisualDataAdapterSP мы создавали и выполняли хранимые процедуры, настраивая DataAdapter без всякого объекта Command! В действительности, среда создала его неявным образом - открываем метод InitializeComponent и видим объявление sqlSelectCommand1, а также описание нескольких его свойств:
private void InitializeComponent()
{
...
this.sqlSelectCommand1 = new System.Data.SqlClient.SqlCommand();
...
//
// sqlSelectCommand1
//
this.sqlSelectCommand1.CommandText = "[proc_da1]";
this.sqlSelectCommand1.CommandType = System.Data.CommandType.StoredProcedure;
this.sqlSelectCommand1.Connection = this.sqlConnection1;
this.sqlSelectCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter
("@RETURN_VALUE", System.Data.SqlDbType.Int, 4,
System.Data.ParameterDirection.ReturnValue, false, ((System.Byte)(0)),
((System.Byte)(0)), "", System.Data.DataRowVersion.Current, null));
...
Нам нужно научиться понимать это описание и создавать его программным образом. Среда Visual Studio .NET содержит инструменты для визуальной настройки объекта Command, и поскольку разобраться в них проще, чем в коде, начнем с них. Создайте новое Windows-приложение и назовите его "VisualCommand". Добавляем элемент управления DataGrid, его свойству Dock устанавливаем значение Fill. В окне ToolBox переходим на вкладку Data, перетаскиваем на форму объект SqlCommand (рис. 6.1):
(рис 6.1) Окно Toolbox, вкладка Data Переходим в окно Properties появившегося объекта sqlCommand1, в свойстве "Connection" из выпадающего списка выбираем создание нового подключения (New) (рис. 6.2).
(рис 6.2) Свойство "Connection" объекта sqlCommand1В окне "Свойства связи с данными" настраиваем подключение к базе данных BDTur_firm2 (см. рис. 5.18). На панели компонент появляется объект sqlConnection1 - если бы мы вначале создали и настроили подключение, то в свойстве Connection объекта sqlCommand1 можно было выбрать "Existing/sqlConnection1". Свойство CommandType указывает на тип команды (запроса), который будет направляться к базе данных (рис. 6.3):
(рис 6.3) Свойство CommandType объекта sqlCommand1Возможны следующие значения:
Text. Текстовая команда состоит из SQL-конструкции, направляемой к базе данных. Это значение используется по умолчанию.StoredProcedure. Текстовая команда состоит из названия хранимой процедуры.TableDirect. Текстовая команда состоит из названия таблицы базы данных. В результате извлекается все содержимое таблицы. Эта команда аналогична текстовой команде SELECT * FROM Название_таблицы. Команда TableDirect поддерживается только управляемым поставщиком OLE DB.Оставляем пока значение по умолчанию. В поле свойства (...) (рис. 6.4):
(рис 6.4) Свойство CommandText объекта sqlCommand1В появившемся построителе выражений настраиваем извлечение содержимого таблицы "Туры". Обратите внимание на то, что в поле свойства CommandText появилась SQL-конструкция:
SELECT Туры.* FROM Туры
Снова в окне Toolbox переходим на вкладку Data, перетаскиваем на форму объект SqlDataAdapter. В мастере "Data sqlCommand1 (рис. 6.5):
(рис 6.5) Свойство SelectCommand объекта sqlDataAdapter1 Выделяем sqlDataAdapter1, создаем DataSet, нажимая на ссылку "Generate Dataset". В окне "Generate Dataset" оставляем название "DataSet1", нажимаем "OK". В выпадающем списке свойства DataSource элемента управления DataGrid выбираем "datSet11" в качестве источника данных (рис. 6.6):
(рис 6.6) Свойство DataSource элемента dataGrid1Наконец в конструкторе формы вызываем метод Fill объекта DataAdapter:
public Form1()
{
InitializeComponent();
sqlDataAdapter1.Fill(dataSet11);
}
Запускаем приложение. На форму выводится содержимое таблицы "Туры" (рис. 6.7):
(рис 6.7) Приложение VisualCommand, вывод таблицы "Туры"Установим теперь в свойстве CommandType объекта Command значение "StoredProcedure", а в свойстве CommandText введем название имеющейся хранимой процедуры - "[proc10]" (рис. 6.8):
(рис 6.8) Настройка свойств объекта sqlCommand1 для вывода процедуры [proc10]Чтобы избежать проблем со структурой DataSet, удалим имеющийся объект с панели компонент. Дополнительно в окне Solution Explorer удаляем файл DataSet1.xsd. Снова генерируем DataSet и определяем его в качестве источника данных для элемента DataGrid. Запускаем приложение - на форму выводится результат
(рис 6.9) Приложение VisualCommand, извлечение хранимой процедуры proc10Таким образом можно извлекать данные из таблиц при помощи SQL-конструкций и запускать хранимые процедуры таблицы 5.1. Поставщик данных SQL Server не поддерживает значение TableDirect свойства CommandType - при его выборе появляется диагностическое сообщение об ошибке. Это значение можно применять при подключении к базе данных Microsoft Access.
В программном обеспечении к курсу вы найдете приложение Visual Command (Code\Glava3\ VisualCommand).
Перейдем теперь к реализации аналогичного приложения без применения визуальных средств студии для объектов ADO .NET. Создайте новое Windows-приложение и назовите его "ProgrammCommand". Перетаскиваем на форму элемент управления DataGrid, его свойству Dock устанавливаем значение "Fill". В классе формы создаем строки connectionString и commandText:
string connectionString = "integrated security=SSPI; data source=\".\"; persist security info=False; initial catalog=BDTur_firm2"; string commandText = "SELECT * FROM Туры";
Конструктор формы будет иметь следующий вид:
public Form1()
{
InitializeComponent();
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand myCommand = new SqlCommand();
myCommand.Connection = conn;
myCommand.CommandText = commandText;
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
conn.Open();
dataAdapter.Fill(ds, "Туры");
conn.Close();
dataGrid1.DataSource = ds;
}
Запускаем приложение. На форму выводится содержимое таблицы "Туры" (см. рис. 6.7). Здесь мы используем всего один объект DataAdapter, который сам открывает и закрывает соединение для получения данных. Поэтому можно не вызывать методы Open и Close объекта conn. Конструктор объекта SqlCommand может принимать значения, указанные в таблице 6.1.
| № | Вид | |
|---|---|---|
| 1 | ![]() |
|
| Описание | ||
public Form1()
{
InitializeComponent();
SqlConnection conn =
new SqlConnection(connectionString);
SqlTransaction trans = conn.BeginTransaction();
SqlCommand myCommand =
new SqlCommand(commandText, conn, trans);
//SqlCommand myCommand =
// new SqlCommand("SELECT * FROM Туры", conn, trans);
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Первый параметр - строка commandText, причем можно сразу задавать SQL-конструкцию без и SqlTransaction. Подробно о транзакциях см. далее |
|
| № | Вид | |
| 2 | ![]() |
|
| Пример | Описание | |
public Form1()
{
InitializeComponent();
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand =
new SqlCommand(commandText, conn);
//SqlCommand myCommand =
// new SqlCommand("SELECT * FROM Туры", conn);
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Вариант без экземпляра объекта SqlTransaction |
|
| № | Вид | |
| 3 | ![]() |
|
| Пример | Описание | |
public Form1()
{
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand =
new SqlCommand(commandText);
//SqlCommand myCommand =
// new SqlCommand("SELECT * FROM Туры");
myCommand.Connection = conn;
SqlDataAdapter dataAdapter =
new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Конструктор принимает в качестве параметра только строку commandText. Для указания соединений используем свойство Connection созданного экзмепляра myCommand |
|
| № | Вид | |
| 4 | ![]() |
|
| Пример | Описание | |
public Form1()
{
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand = new SqlCommand();
myCommand.Connection = conn;
myCommand.CommandText = commandText;
//Command.CommandText = "SELECT * FROM Туры";
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Конструктор не принимает параметров. Для указания соединения и строки commandText вызываем соответствующие свойства созданного экземпляра myCommand. Строке commandText можно передать SQL-конструкцию непосредственно - в этом случае создавать переменную в классе не нужно |
|
Первый вариант конструктора обеспечивает самую компактную форму записи. Его можно использовать при работе с одним соединением с базой данных. В случае работы с несколькими соединениями удобнее определить значения командных строк в классе формы (или вообще в отдельном классе) и использовать четвертый вариант. При изменении параметров подключения нужно будет исправить только сами строки, не затрагивая код, относящийся к объекту Command.
Для вывода хранимой процедуры следует указать значение "Stored Procedure" свойства CommandType:
public Form1()
{
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand =
new SqlCommand();
myCommand.Connection = conn;
myCommand.CommandType =
CommandType.StoredProcedure;
myCommand.CommandText = "[proc10]";
SqlDataAdapter dataAdapter =
new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
Название процедуры можно также присвоить переменной commandText, созданной в классе формы.
В программном обеспечении к курсу вы найдете приложение Programm Command (Code\Glava3\ ProgrammCommand).
Мы рассмотрели всю возможную функциональность, которую можно получить без использования каких-либо методов объекта Command. Для выполнения запросов на выборку простейших процедур достаточно просто указать тип и передать название запроса или процедуры. Все работает, но этого явно недостаточно для серьезных приложений. Поэтому забудем пока про хранимые процедуры, другие объекты ADO .NET, и сосредоточим все внимание на методах объекта Command.
Метод ExecuteNonQuery применяется для выполнения запросов, не возвращающих данные. Как же запросы, предназначенные именно для извлечения данных, могут не возвращать их? Речь идет о запросах типа UPDATE, INSERT и DELETE - в самом деле, они вносят изменения в таблицу базы данных, не возвращая ничего назад в результате выполнения. В самом языке 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. Язык определения 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 применяется для выполнения запросов, относящихся к категории GRANT, DENY, REVOKE. Мы не будем рассматривать выполнение этих запросов - использование в данном случае объекта Command не отличается ничем от рассмотренного выше.
В программном обеспечении к курсу вы найдете приложение 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);
}
Запускаем
(рис 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 и выводим набор записей в консольное окно. Запускаем
(рис 6.19) Приложение "ExampleExecuteReader". Вывод поля "Фамилия"Объект DataReader возвращает набор данных типа object, причем для обращения можно использовать индекс:
Console.WriteLine(dataReader[1]);
Это совершенно эквивалентная строка
Перечислим несколько полей:
... 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).
Мы рассмотрели основные методы объекта Command в консольных приложениях. Это дало нам возможность понять синтаксис самих методов, без привязки к какому-либо интерфейсу. Однако, после того как синтаксис стал ясен, возникает вопрос - как же использовать эти методы в реальных приложениях? Понятно, что простое копирование кода в конструктор формы, по сути, не изменит пример. Следовательно, мы должны привязывать вводимые значения, например, к текстовым полям. Но это означает, что параметры строки запроса будут неизвестны до тех пор, пока пользователь не введет соответствующие значения. Например, для метода ExecuteNonQuery строка commandText имела следующий вид:
myCommand.CommandText = "UPDATE Туристы SET Фамилия = 'Сергеева' WHERE Кодтуриста = 3";
Если мы создадим приложение, где пользователь будет вводить фамилию и код туриста, то мы не можем заранее указать, какие это будут значения. Логически запрос можно представить примерно так:
myCommand.CommandText = "UPDATE Туристы SET Фамилия = 'Какая-то_фамилия,_которую_введет_пользователь' WHERE Кодтуриста = Какой-то_код,_который_введет_пользователь";
Для решения таких задач, которые возникли еще в самом начале разработки языка SQL, были придуманы параметризированные запросы. В них неизвестные значения заменяются параметрами. Вот так:
myCommand.CommandText = "UPDATE Туристы SET Фамилия = @Family WHERE Кодтуриста = @TouristID";
Здесь @Family (обратите внимание, пишется без кавычек!) - параметр для неизвестного значения фамилии, @TouristID - параметр для неизвестного значения кода туриста. Теперь мы можем привязывать параметры к тексту, вводимому пользователем. Создайте новое Windows-приложение и назовите его "ExamWinExecuteNonQuery". Устанавливаем следующие свойства формы:
| Form1, форма, свойство | Значение |
|---|---|
| FormBorderStyle | FixedSingle |
| MaximizeBox | False |
| Size | 620; 240 |
Добавляем на форму элементы управления и устанавливаем их свойства:
| gropBox1, свойство | Значение |
|---|---|
| Location | 16; 16 |
| Size | 296; 112 |
| Text | Пример UPDATE |
| gropBox2, свойство | Значение |
|---|---|
| Location | 320; 16 |
| Size | 280; 176 |
| Text | Пример INSERT |
| gropBox3, свойство | Значение |
|---|---|
| Location | 16; 136 |
| Size | 296; 56 |
| Text | Пример DELETE |
| button1, свойство | Значение |
|---|---|
| Name | btnUpdate |
| Location | 80; 80 |
| Text | Обновить |
| button2, свойство | Значение |
|---|---|
| Name | btnInsert |
| Location | 88; 144 |
| Text | Добавить |
| button3, свойство | Значение |
|---|---|
| Name | BtnDelete |
| Location | 208; 24 |
| Text | Удалить |
| textBox1, свойство | Значение |
|---|---|
| Name | TxtTouristIDUpdate |
| Location | 16; 24 |
| Size | 224; 20 |
| Text | Введите код туриста |
| textBox2, свойство | Значение |
|---|---|
| Name | TxtFamilyUpdate |
| Location | 16; 56 |
| Size | 224; 20 |
| Text | Введите фамилию туриста |
| textBox3, свойство | Значение |
|---|---|
| Name | TxtTouristIDInsert |
| Location | 16; 24 |
| Size | 224; 20 |
| Text | Введите код туриста |
| textBox4, свойство | Значение |
|---|---|
| Name | TxtFamilyInsert |
| Location | 16; 56 |
| Size | 224; 20 |
| Text | Введите фамилию туриста |
| textBox5, свойство | Значение |
|---|---|
| Name | TxtFirstNameInsert |
| Location | 16; 88 |
| Size | 224; 20 |
| Text | Введите имя туриста |
| textBox6, свойство | Значение |
|---|---|
| Name | TxtMiddleNameInsert |
| Location | 16; 120 |
| Size | 224; 20 |
| Text | Введите отчество туриста |
| textBox7, свойство | Значение |
|---|---|
| Name | txtTouristIDDelete |
| Location | 8; 24 |
| Size | 192; 20 |
| Text | Введите код туриста для удаления |
Форма в режиме дизайна будет иметь следующий вид (рис. 6.22):
(рис 6.22) Приложение ExamWinExecuteNonQuery, вид формы в режиме дизайна Подключаем пространство имен для работы с базой данных:
using System.Data.SqlClient;
В классе формы создаем экземпляр
SqlConnection conn = null;
Обработчик кнопки btnUpdate будет иметь следующий вид:
private void btnUpdate_Click(object sender, System.EventArgs e)
{
try
{
//Создаем переменную Family, в которую помещаем значение,
//введенное пользователем в поле txtFamilyUpdate:
string Family = Convert.ToString(this.txtFamilyUpdate.Text);
//Создаем переменную TouristID, в которую помещаем значение,
//введенное пользователем в поле txtTouristIDUpdate:
int TouristID = int.Parse(this.txtTouristIDUpdate.Text);
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 Фамилия = @Family WHERE Кодтуриста = @TouristID";
//Добавляем параметр @Family в коллекцию параметров
//объекта myCommand
myCommand.Parameters.Add("@Family",
SqlDbType.NVarChar, 50);
//Устанавливаем значение параметра @Family
//равным значению переменной Family
myCommand.Parameters["@Family"].Value = Family;
//Добавляем параметр @TouristID в коллекцию параметров
//объекта myCommand
myCommand.Parameters.Add("@TouristID", SqlDbType.Int, 4);
//Устанавливаем значение параметра @TouristID
//равным значению переменной TouristID
myCommand.Parameters["@TouristID"].Value = TouristID;
int UspeshnoeIzmenenie = myCommand.ExecuteNonQuery();
if (UspeshnoeIzmenenie !=0)
{
MessageBox.Show("Изменения внесены",
"Изменение записи");
}
else
{
MessageBox.Show("Не удалось внести изменения",
"Изменение записи");
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
Обратите внимание - в блоке finally мы закрываем соединение, это нужно сделать в любом случае, независимо от результата выполнения команды. Значения, введенные пользователем в текстовые поля txtFamilyUpdate и txtTouristIDUpdate, помещаются в переменные Family и TouristID. В запросе к базе данных используются два параметра - @Family и @TouristID. Мы добавляем их в коллекцию объекта Command, используя метод Add свойства Parameters, а затем устанавливаем значения параметров равными переменным Family и TouristID. Конструктор метод Add перегружен, первый вариант принимает наибольшее количество
(рис 6.23) Конструктор метода Add свойства Parameters объекта CommandОписание некоторых свойств метода Add приводится в таблице 6.2.
| Свойство | Описание |
|---|---|
| parameterName | Название параметра |
| sqlDbType | Тип данных передаваемого параметра |
| size | Размер параметра |
| sourceColumn | Название имени столбца объекта DataSet, на который ссылается данный параметр |
Конструктор метода Add свойства Parameters объекта Command для поставщика данных OLE DB имеет в точности такую же структуру (рис. 6.24):
(рис 6.24) Конструктор метода Add свойства Parameters объекта Command поставщика данных OLE DBДобавляем обработчик кнопки btnInsert:
private void btnInsert_Click(object sender, System.EventArgs e)
{
try
{
int TouristID = int.Parse(this.txtTouristIDInsert.Text);
string Family = Convert.ToString(this.txtFamilyInsert.Text);
string FirstName = Convert.ToString(this.txtFirstNameInsert.Text);
string MiddleName = Convert.ToString(this.txtMiddleNameInsert.Text);
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 =
"INSERT INTO Туристы (Кодтуриста, Фамилия, Имя, Отчество)
VALUES (@TouristID, @Family, @FirstName, @MiddleName)";
myCommand.Parameters.Add("@TouristID", SqlDbType.Int, 4);
myCommand.Parameters["@TouristID"].Value = TouristID;
myCommand.Parameters.Add("@Family", SqlDbType.NVarChar, 50);
myCommand.Parameters["@Family"].Value = Family;
myCommand.Parameters.Add("@FirstName",
SqlDbType.NVarChar, 50);
myCommand.Parameters["@FirstName"].Value = FirstName;
myCommand.Parameters.Add("@MiddleName",
SqlDbType.NVarChar, 50);
myCommand.Parameters["@MiddleName"].Value = MiddleName;
int UspeshnoeIzmenenie = myCommand.ExecuteNonQuery();
if (UspeshnoeIzmenenie !=0)
{
MessageBox.Show("Изменения внесены",
"Изменение записи");
}
else
{
MessageBox.Show("Не удалось внести изменения",
"Изменение записи");
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
В запросе используются четыре параметра: @TouristID, @Family, @FirstName, @. Тип данных создаваемых параметров соответствует типу данных полей таблицы "Туристы" в базе.
Добавляем обработчик кнопки btnDelete:
private void btnDelete_Click(object sender, System.EventArgs e)
{
try
{
int TouristID = int.Parse(this.txtTouristIDDelete.Text);
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 = "DELETE FROM Туристы
WHERE Кодтуриста = @TouristID";
myCommand.Parameters.Add("@TouristID", SqlDbType.Int, 4);
myCommand.Parameters["@TouristID"].Value = TouristID;
int UspeshnoeIzmenenie = myCommand.ExecuteNonQuery();
if (UspeshnoeIzmenenie !=0)
{
MessageBox.Show("Изменения внесены",
"Изменение записи");
}
else
{
MessageBox.Show("Не удалось внести изменения",
"Изменение записи");
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
Запускаем приложение. В каждой из групп заполняем поля, затем нажимаем на кнопки. Проверять результат можно, запуская SQL Server Enterprise Manager и просматривая каждый раз содержимое таблицы "Туристы" (рис. 6.25):
(рис 6.25) Готовое приложение ExamWinExecuteNonQuery. Таблицы взяты из SQL Server Enterprise ManagerВ программном обеспечении к курсу вы найдете приложение Exam WinExecuteNonQuery (Code\Glava3\ ExamWinExecuteNonQuery).
Применять метод ExecuteScalar объекта Command в Windows-приложениях очень легко - достаточно указать элемент управления (текстовое поле, надпись) для вывода одиночного значения.
Рассмотрим теперь метод (...) (рис. 6.26). В редакторе "Column Header Collection Editor" добавляем следующие четыре элемента:
| Name | Text |
|---|---|
| chTouristID | Код туриста |
| Name | Text |
|---|---|
| chFamily | Фамилия |
| Name | Text |
|---|---|
| chFirstName | Имя |
| Name | Text |
|---|---|
| chMiddleName | Отчество |
(рис 6.26) Свойство Columns элемента ListView и редактор "ColumnHeader Collection Editor"Для отображения созданных столбцов свойству View элемента устанавливаем значение "Details". Также включим режим отображения линий сетки - в свойстве GridLines выбираем значение "True". Сделанные изменения немедленно отобразятся на элементе.
Подключаем пространство имен для работы с базой:
using System.Data.SqlClient;
В классе формы создаем объекты conn и dataReader:
SqlConnection conn = null; SqlDataReader dataReader;
В конструкторе формы добавляем код для заполнения данными элементов управления:
public Form1()
{
InitializeComponent();
try
{
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 = "SELECT * FROM Туристы";
dataReader = myCommand.ExecuteReader();
while (dataReader.Read())
{
// Создаем переменные, получаем для них значения
//из объекта dataReader, используя метод GetТипДанных
int TouristID = dataReader.GetInt32(0);
string Family = dataReader.GetString(1);
string FirstName = dataReader.GetString(2);
string MiddleName = dataReader.GetString(3);
//Выводим данные в элемент listBox1
listBox1.Items.Add("Код туриста: " + TouristID+
" Фамилия: " + Family + " Имя: "+
FirstName + " Отчество: " + MiddleName);
//Создаем экземпляр item класса ListViewItem
//для записи в него данных из dataReader
ListViewItem item =
new ListViewItem(new string[]{Convert.ToString(dataReader[0]),
Convert.ToString(dataReader[1]), Convert.ToString(dataReader[2]),
Convert.ToString(dataReader[3])});
listView1.Items.Add(item);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
dataReader.Close();
conn.Close();
}
}
Метод "GetТипДанных" позволяет приводить значения, возвращаемые объектом DataReader, если заранее известен их тип данных. Запускаем приложение. На форму выводятся данные в виде списка в элементе ListBox и в виде таблицы в элементе ListView (рис. 6.27):
(рис 6.27) Приложение ExamWinExecuteReader В программном обеспечении к курсу вы найдете приложение ExamWin ExecuteReader (Code\Glava3\ ExamWinExecuteReader).
Вывод данных в элемент ListView приводит к достаточно удовлетворительному результату, однако более привычным для нас является вывод в элемент DataGrid. Раньше, при использовании объекта DataSet, мы указывали источник данных для элемента DataGrid так:
dataGrid1.DataSource = dataset.Tables["Название_таблицы"].DefaultView;
Или так:
dataGrid1.DataSource = dataset;
Объект DataReader не поддерживает аналогичного вывода - мы не можем связать объекты таким простым образом:
dataGrid1.DataSource = datareader;
Одним из способов вывода является применение дополнительных объектов DataTable. Объект DataTable предназначен для хранения таблицы, полученной из базы данных (в восьмой лекции мы рассмотрим подробно этот объект). Создайте новое приложение и назовите его "DataReaderToDataGrid". Перетаскиваем на форму элемент управления DataGrid, его свойству Dock устанавливаем значение "Fill". Подключаем пространство имен для работы с базой:
using System.Data.SqlClient;
В классе формы создаем следующие объекты:
SqlConnection conn = null; //Создаем экземпляр FullDataTable, в который будут помещаться данные DataTable FullDataTable = new DataTable(); //Создаем экземпляр ShemaDataTable для получения структуры таблицы из базы данных DataTable ShemaDataTable = new DataTable(); SqlDataReader dataReader; SqlCommand myCommand; //Создаем объект objectRow для получения информации о числе столбцов object[] objectRow;
Основной код помещаем в конструктор формы:
public Form1()
{
InitializeComponent();
try
{
conn = new SqlConnection();
conn.ConnectionString = "integrated security=SSPI;data
source=\".\"; persist security info=False;
initial catalog=BDTur_firm2";
conn.Open();
myCommand = conn.CreateCommand();
myCommand.CommandText = "SELECT * FROM Туристы";
dataReader = myCommand.ExecuteReader();
//Вызываем метод GetSchemaTable, который получает схему таблицы из базы
//и передает ее объекту ShemaDataTable
ShemaDataTable = dataReader.GetSchemaTable();
//Свойство FieldCount возвращает число столбцов для текущей записи.
//Передаем это значение объекту objectRow
objectRow = new object[dataReader.FieldCount];
//Определяем структуру объекта FullDataTable
for(int i =0; i <dataReader.FieldCount; i++)
{
FullDataTable.Columns.Add(ShemaDataTable.Rows[i]
["ColumnName"].ToString(),
((System.Type)ShemaDataTable.Rows[i] ["DataType"]));
}
//Добавляем записи в объект FullDataTable
while(dataReader.Read())
{
dataReader.GetValues(objectRow);
myDataRow = FullDataTable.Rows.Add(objectRow);
}
//Определяем источник данных для элемента dataGrid1
dataGrid1.DataSource = FullDataTable;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
dataReader.Close();
conn.Close();
}
}
Возможно, этот код показался вам сложным. Лучше будет к нему вернуться еще раз после изучения девятой лекции. Запускаем приложение (рис. 6.28):
(рис 6.28) Приложение DataReaderToDataGridВ программном обеспечении к курсу вы найдете приложение Data ReaderToDataGrid (Code\Glava3\ DataReaderToDataGrid).
При определении объектов ADO .NET мы назвали DataAdapter адаптером, преобразователем, предназначенным для взаимодействия с базой данных. Это действительно так, однако если рассматривать взаимодействие с базой данных более глубоко, то выясняется, что в ADO .NET есть специализированный объект для выполнения запросов, называемый Command. Под запросами понимается выполнение SQL-конструкций или запуск хранимых процедур. С объектом Command мы познакомились еще во второй лекции, но у вас могло сложиться впечатление, что его введение достаточно формально - вполне можно обойтись одним объектом DataAdapter. Например, в приложении VisualDataAdapterSP мы создавали и выполняли хранимые процедуры, настраивая DataAdapter без всякого объекта Command! В действительности, среда создала его неявным образом - открываем метод InitializeComponent и видим объявление sqlSelectCommand1, а также описание нескольких его свойств:
private void InitializeComponent()
{
...
this.sqlSelectCommand1 = new System.Data.SqlClient.SqlCommand();
...
//
// sqlSelectCommand1
//
this.sqlSelectCommand1.CommandText = "[proc_da1]";
this.sqlSelectCommand1.CommandType = System.Data.CommandType.StoredProcedure;
this.sqlSelectCommand1.Connection = this.sqlConnection1;
this.sqlSelectCommand1.Parameters.Add(new System.Data.SqlClient.SqlParameter
("@RETURN_VALUE", System.Data.SqlDbType.Int, 4,
System.Data.ParameterDirection.ReturnValue, false, ((System.Byte)(0)),
((System.Byte)(0)), "", System.Data.DataRowVersion.Current, null));
...
Нам нужно научиться понимать это описание и создавать его программным образом. Среда Visual Studio .NET содержит инструменты для визуальной настройки объекта Command, и поскольку разобраться в них проще, чем в коде, начнем с них. Создайте новое Windows-приложение и назовите его "VisualCommand". Добавляем элемент управления DataGrid, его свойству Dock устанавливаем значение Fill. В окне ToolBox переходим на вкладку Data, перетаскиваем на форму объект SqlCommand (рис. 6.1):
(рис 6.1) Окно Toolbox, вкладка Data Переходим в окно Properties появившегося объекта sqlCommand1, в свойстве "Connection" из выпадающего списка выбираем создание нового подключения (New) (рис. 6.2).
(рис 6.2) Свойство "Connection" объекта sqlCommand1В окне "Свойства связи с данными" настраиваем подключение к базе данных BDTur_firm2 (см. рис. 5.18). На панели компонент появляется объект sqlConnection1 - если бы мы вначале создали и настроили подключение, то в свойстве Connection объекта sqlCommand1 можно было выбрать "Existing/sqlConnection1". Свойство CommandType указывает на тип команды (запроса), который будет направляться к базе данных (рис. 6.3):
(рис 6.3) Свойство CommandType объекта sqlCommand1Возможны следующие значения:
Text. Текстовая команда состоит из SQL-конструкции, направляемой к базе данных. Это значение используется по умолчанию.StoredProcedure. Текстовая команда состоит из названия хранимой процедуры.TableDirect. Текстовая команда состоит из названия таблицы базы данных. В результате извлекается все содержимое таблицы. Эта команда аналогична текстовой команде SELECT * FROM Название_таблицы. Команда TableDirect поддерживается только управляемым поставщиком OLE DB.Оставляем пока значение по умолчанию. В поле свойства (...) (рис. 6.4):
(рис 6.4) Свойство CommandText объекта sqlCommand1В появившемся построителе выражений настраиваем извлечение содержимого таблицы "Туры". Обратите внимание на то, что в поле свойства CommandText появилась SQL-конструкция:
SELECT Туры.* FROM Туры
Снова в окне Toolbox переходим на вкладку Data, перетаскиваем на форму объект SqlDataAdapter. В мастере "Data sqlCommand1 (рис. 6.5):
(рис 6.5) Свойство SelectCommand объекта sqlDataAdapter1 Выделяем sqlDataAdapter1, создаем DataSet, нажимая на ссылку "Generate Dataset". В окне "Generate Dataset" оставляем название "DataSet1", нажимаем "OK". В выпадающем списке свойства DataSource элемента управления DataGrid выбираем "datSet11" в качестве источника данных (рис. 6.6):
(рис 6.6) Свойство DataSource элемента dataGrid1Наконец в конструкторе формы вызываем метод Fill объекта DataAdapter:
public Form1()
{
InitializeComponent();
sqlDataAdapter1.Fill(dataSet11);
}
Запускаем приложение. На форму выводится содержимое таблицы "Туры" (рис. 6.7):
(рис 6.7) Приложение VisualCommand, вывод таблицы "Туры"Установим теперь в свойстве CommandType объекта Command значение "StoredProcedure", а в свойстве CommandText введем название имеющейся хранимой процедуры - "[proc10]" (рис. 6.8):
(рис 6.8) Настройка свойств объекта sqlCommand1 для вывода процедуры [proc10]Чтобы избежать проблем со структурой DataSet, удалим имеющийся объект с панели компонент. Дополнительно в окне Solution Explorer удаляем файл DataSet1.xsd. Снова генерируем DataSet и определяем его в качестве источника данных для элемента DataGrid. Запускаем приложение - на форму выводится результат
(рис 6.9) Приложение VisualCommand, извлечение хранимой процедуры proc10Таким образом можно извлекать данные из таблиц при помощи SQL-конструкций и запускать хранимые процедуры таблицы 5.1. Поставщик данных SQL Server не поддерживает значение TableDirect свойства CommandType - при его выборе появляется диагностическое сообщение об ошибке. Это значение можно применять при подключении к базе данных Microsoft Access.
В программном обеспечении к курсу вы найдете приложение Visual Command (Code\Glava3\ VisualCommand).
Перейдем теперь к реализации аналогичного приложения без применения визуальных средств студии для объектов ADO .NET. Создайте новое Windows-приложение и назовите его "ProgrammCommand". Перетаскиваем на форму элемент управления DataGrid, его свойству Dock устанавливаем значение "Fill". В классе формы создаем строки connectionString и commandText:
string connectionString = "integrated security=SSPI; data source=\".\"; persist security info=False; initial catalog=BDTur_firm2"; string commandText = "SELECT * FROM Туры";
Конструктор формы будет иметь следующий вид:
public Form1()
{
InitializeComponent();
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand myCommand = new SqlCommand();
myCommand.Connection = conn;
myCommand.CommandText = commandText;
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
conn.Open();
dataAdapter.Fill(ds, "Туры");
conn.Close();
dataGrid1.DataSource = ds;
}
Запускаем приложение. На форму выводится содержимое таблицы "Туры" (см. рис. 6.7). Здесь мы используем всего один объект DataAdapter, который сам открывает и закрывает соединение для получения данных. Поэтому можно не вызывать методы Open и Close объекта conn. Конструктор объекта SqlCommand может принимать значения, указанные в таблице 6.1.
| № | Вид | |
|---|---|---|
| 1 | ![]() |
|
| Описание | ||
public Form1()
{
InitializeComponent();
SqlConnection conn =
new SqlConnection(connectionString);
SqlTransaction trans = conn.BeginTransaction();
SqlCommand myCommand =
new SqlCommand(commandText, conn, trans);
//SqlCommand myCommand =
// new SqlCommand("SELECT * FROM Туры", conn, trans);
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Первый параметр - строка commandText, причем можно сразу задавать SQL-конструкцию без и SqlTransaction. Подробно о транзакциях см. далее |
|
| № | Вид | |
| 2 | ![]() |
|
| Пример | Описание | |
public Form1()
{
InitializeComponent();
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand =
new SqlCommand(commandText, conn);
//SqlCommand myCommand =
// new SqlCommand("SELECT * FROM Туры", conn);
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Вариант без экземпляра объекта SqlTransaction |
|
| № | Вид | |
| 3 | ![]() |
|
| Пример | Описание | |
public Form1()
{
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand =
new SqlCommand(commandText);
//SqlCommand myCommand =
// new SqlCommand("SELECT * FROM Туры");
myCommand.Connection = conn;
SqlDataAdapter dataAdapter =
new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Конструктор принимает в качестве параметра только строку commandText. Для указания соединений используем свойство Connection созданного экзмепляра myCommand |
|
| № | Вид | |
| 4 | ![]() |
|
| Пример | Описание | |
public Form1()
{
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand = new SqlCommand();
myCommand.Connection = conn;
myCommand.CommandText = commandText;
//Command.CommandText = "SELECT * FROM Туры";
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
|
Конструктор не принимает параметров. Для указания соединения и строки commandText вызываем соответствующие свойства созданного экземпляра myCommand. Строке commandText можно передать SQL-конструкцию непосредственно - в этом случае создавать переменную в классе не нужно |
|
Первый вариант конструктора обеспечивает самую компактную форму записи. Его можно использовать при работе с одним соединением с базой данных. В случае работы с несколькими соединениями удобнее определить значения командных строк в классе формы (или вообще в отдельном классе) и использовать четвертый вариант. При изменении параметров подключения нужно будет исправить только сами строки, не затрагивая код, относящийся к объекту Command.
Для вывода хранимой процедуры следует указать значение "Stored Procedure" свойства CommandType:
public Form1()
{
SqlConnection conn =
new SqlConnection(connectionString);
SqlCommand myCommand =
new SqlCommand();
myCommand.Connection = conn;
myCommand.CommandType =
CommandType.StoredProcedure;
myCommand.CommandText = "[proc10]";
SqlDataAdapter dataAdapter =
new SqlDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "Туры");
dataGrid1.DataSource = ds;
}
Название процедуры можно также присвоить переменной commandText, созданной в классе формы.
В программном обеспечении к курсу вы найдете приложение Programm Command (Code\Glava3\ ProgrammCommand).
Мы рассмотрели всю возможную функциональность, которую можно получить без использования каких-либо методов объекта Command. Для выполнения запросов на выборку простейших процедур достаточно просто указать тип и передать название запроса или процедуры. Все работает, но этого явно недостаточно для серьезных приложений. Поэтому забудем пока про хранимые процедуры, другие объекты ADO .NET, и сосредоточим все внимание на методах объекта Command.
Метод ExecuteNonQuery применяется для выполнения запросов, не возвращающих данные. Как же запросы, предназначенные именно для извлечения данных, могут не возвращать их? Речь идет о запросах типа UPDATE, INSERT и DELETE - в самом деле, они вносят изменения в таблицу базы данных, не возвращая ничего назад в результате выполнения. В самом языке 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. Язык определения 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 применяется для выполнения запросов, относящихся к категории GRANT, DENY, REVOKE. Мы не будем рассматривать выполнение этих запросов - использование в данном случае объекта Command не отличается ничем от рассмотренного выше.
В программном обеспечении к курсу вы найдете приложение 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);
}
Запускаем
(рис 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 и выводим набор записей в консольное окно. Запускаем
(рис 6.19) Приложение "ExampleExecuteReader". Вывод поля "Фамилия"Объект DataReader возвращает набор данных типа object, причем для обращения можно использовать индекс:
Console.WriteLine(dataReader[1]);
Это совершенно эквивалентная строка
Перечислим несколько полей:
... 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).
Мы рассмотрели основные методы объекта Command в консольных приложениях. Это дало нам возможность понять синтаксис самих методов, без привязки к какому-либо интерфейсу. Однако, после того как синтаксис стал ясен, возникает вопрос - как же использовать эти методы в реальных приложениях? Понятно, что простое копирование кода в конструктор формы, по сути, не изменит пример. Следовательно, мы должны привязывать вводимые значения, например, к текстовым полям. Но это означает, что параметры строки запроса будут неизвестны до тех пор, пока пользователь не введет соответствующие значения. Например, для метода ExecuteNonQuery строка commandText имела следующий вид:
myCommand.CommandText = "UPDATE Туристы SET Фамилия = 'Сергеева' WHERE Кодтуриста = 3";
Если мы создадим приложение, где пользователь будет вводить фамилию и код туриста, то мы не можем заранее указать, какие это будут значения. Логически запрос можно представить примерно так:
myCommand.CommandText = "UPDATE Туристы SET Фамилия = 'Какая-то_фамилия,_которую_введет_пользователь' WHERE Кодтуриста = Какой-то_код,_который_введет_пользователь";
Для решения таких задач, которые возникли еще в самом начале разработки языка SQL, были придуманы параметризированные запросы. В них неизвестные значения заменяются параметрами. Вот так:
myCommand.CommandText = "UPDATE Туристы SET Фамилия = @Family WHERE Кодтуриста = @TouristID";
Здесь @Family (обратите внимание, пишется без кавычек!) - параметр для неизвестного значения фамилии, @TouristID - параметр для неизвестного значения кода туриста. Теперь мы можем привязывать параметры к тексту, вводимому пользователем. Создайте новое Windows-приложение и назовите его "ExamWinExecuteNonQuery". Устанавливаем следующие свойства формы:
| Form1, форма, свойство | Значение |
|---|---|
| FormBorderStyle | FixedSingle |
| MaximizeBox | False |
| Size | 620; 240 |
Добавляем на форму элементы управления и устанавливаем их свойства:
| gropBox1, свойство | Значение |
|---|---|
| Location | 16; 16 |
| Size | 296; 112 |
| Text | Пример UPDATE |
| gropBox2, свойство | Значение |
|---|---|
| Location | 320; 16 |
| Size | 280; 176 |
| Text | Пример INSERT |
| gropBox3, свойство | Значение |
|---|---|
| Location | 16; 136 |
| Size | 296; 56 |
| Text | Пример DELETE |
| button1, свойство | Значение |
|---|---|
| Name | btnUpdate |
| Location | 80; 80 |
| Text | Обновить |
| button2, свойство | Значение |
|---|---|
| Name | btnInsert |
| Location | 88; 144 |
| Text | Добавить |
| button3, свойство | Значение |
|---|---|
| Name | BtnDelete |
| Location | 208; 24 |
| Text | Удалить |
| textBox1, свойство | Значение |
|---|---|
| Name | TxtTouristIDUpdate |
| Location | 16; 24 |
| Size | 224; 20 |
| Text | Введите код туриста |
| textBox2, свойство | Значение |
|---|---|
| Name | TxtFamilyUpdate |
| Location | 16; 56 |
| Size | 224; 20 |
| Text | Введите фамилию туриста |
| textBox3, свойство | Значение |
|---|---|
| Name | TxtTouristIDInsert |
| Location | 16; 24 |
| Size | 224; 20 |
| Text | Введите код туриста |
| textBox4, свойство | Значение |
|---|---|
| Name | TxtFamilyInsert |
| Location | 16; 56 |
| Size | 224; 20 |
| Text | Введите фамилию туриста |
| textBox5, свойство | Значение |
|---|---|
| Name | TxtFirstNameInsert |
| Location | 16; 88 |
| Size | 224; 20 |
| Text | Введите имя туриста |
| textBox6, свойство | Значение |
|---|---|
| Name | TxtMiddleNameInsert |
| Location | 16; 120 |
| Size | 224; 20 |
| Text | Введите отчество туриста |
| textBox7, свойство | Значение |
|---|---|
| Name | txtTouristIDDelete |
| Location | 8; 24 |
| Size | 192; 20 |
| Text | Введите код туриста для удаления |
Форма в режиме дизайна будет иметь следующий вид (рис. 6.22):
(рис 6.22) Приложение ExamWinExecuteNonQuery, вид формы в режиме дизайна Подключаем пространство имен для работы с базой данных:
using System.Data.SqlClient;
В классе формы создаем экземпляр
SqlConnection conn = null;
Обработчик кнопки btnUpdate будет иметь следующий вид:
private void btnUpdate_Click(object sender, System.EventArgs e)
{
try
{
//Создаем переменную Family, в которую помещаем значение,
//введенное пользователем в поле txtFamilyUpdate:
string Family = Convert.ToString(this.txtFamilyUpdate.Text);
//Создаем переменную TouristID, в которую помещаем значение,
//введенное пользователем в поле txtTouristIDUpdate:
int TouristID = int.Parse(this.txtTouristIDUpdate.Text);
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 Фамилия = @Family WHERE Кодтуриста = @TouristID";
//Добавляем параметр @Family в коллекцию параметров
//объекта myCommand
myCommand.Parameters.Add("@Family",
SqlDbType.NVarChar, 50);
//Устанавливаем значение параметра @Family
//равным значению переменной Family
myCommand.Parameters["@Family"].Value = Family;
//Добавляем параметр @TouristID в коллекцию параметров
//объекта myCommand
myCommand.Parameters.Add("@TouristID", SqlDbType.Int, 4);
//Устанавливаем значение параметра @TouristID
//равным значению переменной TouristID
myCommand.Parameters["@TouristID"].Value = TouristID;
int UspeshnoeIzmenenie = myCommand.ExecuteNonQuery();
if (UspeshnoeIzmenenie !=0)
{
MessageBox.Show("Изменения внесены",
"Изменение записи");
}
else
{
MessageBox.Show("Не удалось внести изменения",
"Изменение записи");
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
Обратите внимание - в блоке finally мы закрываем соединение, это нужно сделать в любом случае, независимо от результата выполнения команды. Значения, введенные пользователем в текстовые поля txtFamilyUpdate и txtTouristIDUpdate, помещаются в переменные Family и TouristID. В запросе к базе данных используются два параметра - @Family и @TouristID. Мы добавляем их в коллекцию объекта Command, используя метод Add свойства Parameters, а затем устанавливаем значения параметров равными переменным Family и TouristID. Конструктор метод Add перегружен, первый вариант принимает наибольшее количество
(рис 6.23) Конструктор метода Add свойства Parameters объекта CommandОписание некоторых свойств метода Add приводится в таблице 6.2.
| Свойство | Описание |
|---|---|
| parameterName | Название параметра |
| sqlDbType | Тип данных передаваемого параметра |
| size | Размер параметра |
| sourceColumn | Название имени столбца объекта DataSet, на который ссылается данный параметр |
Конструктор метода Add свойства Parameters объекта Command для поставщика данных OLE DB имеет в точности такую же структуру (рис. 6.24):
(рис 6.24) Конструктор метода Add свойства Parameters объекта Command поставщика данных OLE DBДобавляем обработчик кнопки btnInsert:
private void btnInsert_Click(object sender, System.EventArgs e)
{
try
{
int TouristID = int.Parse(this.txtTouristIDInsert.Text);
string Family = Convert.ToString(this.txtFamilyInsert.Text);
string FirstName = Convert.ToString(this.txtFirstNameInsert.Text);
string MiddleName = Convert.ToString(this.txtMiddleNameInsert.Text);
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 =
"INSERT INTO Туристы (Кодтуриста, Фамилия, Имя, Отчество)
VALUES (@TouristID, @Family, @FirstName, @MiddleName)";
myCommand.Parameters.Add("@TouristID", SqlDbType.Int, 4);
myCommand.Parameters["@TouristID"].Value = TouristID;
myCommand.Parameters.Add("@Family", SqlDbType.NVarChar, 50);
myCommand.Parameters["@Family"].Value = Family;
myCommand.Parameters.Add("@FirstName",
SqlDbType.NVarChar, 50);
myCommand.Parameters["@FirstName"].Value = FirstName;
myCommand.Parameters.Add("@MiddleName",
SqlDbType.NVarChar, 50);
myCommand.Parameters["@MiddleName"].Value = MiddleName;
int UspeshnoeIzmenenie = myCommand.ExecuteNonQuery();
if (UspeshnoeIzmenenie !=0)
{
MessageBox.Show("Изменения внесены",
"Изменение записи");
}
else
{
MessageBox.Show("Не удалось внести изменения",
"Изменение записи");
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
В запросе используются четыре параметра: @TouristID, @Family, @FirstName, @. Тип данных создаваемых параметров соответствует типу данных полей таблицы "Туристы" в базе.
Добавляем обработчик кнопки btnDelete:
private void btnDelete_Click(object sender, System.EventArgs e)
{
try
{
int TouristID = int.Parse(this.txtTouristIDDelete.Text);
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 = "DELETE FROM Туристы
WHERE Кодтуриста = @TouristID";
myCommand.Parameters.Add("@TouristID", SqlDbType.Int, 4);
myCommand.Parameters["@TouristID"].Value = TouristID;
int UspeshnoeIzmenenie = myCommand.ExecuteNonQuery();
if (UspeshnoeIzmenenie !=0)
{
MessageBox.Show("Изменения внесены",
"Изменение записи");
}
else
{
MessageBox.Show("Не удалось внести изменения",
"Изменение записи");
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
Запускаем приложение. В каждой из групп заполняем поля, затем нажимаем на кнопки. Проверять результат можно, запуская SQL Server Enterprise Manager и просматривая каждый раз содержимое таблицы "Туристы" (рис. 6.25):
(рис 6.25) Готовое приложение ExamWinExecuteNonQuery. Таблицы взяты из SQL Server Enterprise ManagerВ программном обеспечении к курсу вы найдете приложение Exam WinExecuteNonQuery (Code\Glava3\ ExamWinExecuteNonQuery).
Применять метод ExecuteScalar объекта Command в Windows-приложениях очень легко - достаточно указать элемент управления (текстовое поле, надпись) для вывода одиночного значения.
Рассмотрим теперь метод (...) (рис. 6.26). В редакторе "Column Header Collection Editor" добавляем следующие четыре элемента:
| Name | Text |
|---|---|
| chTouristID | Код туриста |
| Name | Text |
|---|---|
| chFamily | Фамилия |
| Name | Text |
|---|---|
| chFirstName | Имя |
| Name | Text |
|---|---|
| chMiddleName | Отчество |
(рис 6.26) Свойство Columns элемента ListView и редактор "ColumnHeader Collection Editor"Для отображения созданных столбцов свойству View элемента устанавливаем значение "Details". Также включим режим отображения линий сетки - в свойстве GridLines выбираем значение "True". Сделанные изменения немедленно отобразятся на элементе.
Подключаем пространство имен для работы с базой:
using System.Data.SqlClient;
В классе формы создаем объекты conn и dataReader:
SqlConnection conn = null; SqlDataReader dataReader;
В конструкторе формы добавляем код для заполнения данными элементов управления:
public Form1()
{
InitializeComponent();
try
{
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 = "SELECT * FROM Туристы";
dataReader = myCommand.ExecuteReader();
while (dataReader.Read())
{
// Создаем переменные, получаем для них значения
//из объекта dataReader, используя метод GetТипДанных
int TouristID = dataReader.GetInt32(0);
string Family = dataReader.GetString(1);
string FirstName = dataReader.GetString(2);
string MiddleName = dataReader.GetString(3);
//Выводим данные в элемент listBox1
listBox1.Items.Add("Код туриста: " + TouristID+
" Фамилия: " + Family + " Имя: "+
FirstName + " Отчество: " + MiddleName);
//Создаем экземпляр item класса ListViewItem
//для записи в него данных из dataReader
ListViewItem item =
new ListViewItem(new string[]{Convert.ToString(dataReader[0]),
Convert.ToString(dataReader[1]), Convert.ToString(dataReader[2]),
Convert.ToString(dataReader[3])});
listView1.Items.Add(item);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
dataReader.Close();
conn.Close();
}
}
Метод "GetТипДанных" позволяет приводить значения, возвращаемые объектом DataReader, если заранее известен их тип данных. Запускаем приложение. На форму выводятся данные в виде списка в элементе ListBox и в виде таблицы в элементе ListView (рис. 6.27):
(рис 6.27) Приложение ExamWinExecuteReader В программном обеспечении к курсу вы найдете приложение ExamWin ExecuteReader (Code\Glava3\ ExamWinExecuteReader).
Вывод данных в элемент ListView приводит к достаточно удовлетворительному результату, однако более привычным для нас является вывод в элемент DataGrid. Раньше, при использовании объекта DataSet, мы указывали источник данных для элемента DataGrid так:
dataGrid1.DataSource = dataset.Tables["Название_таблицы"].DefaultView;
Или так:
dataGrid1.DataSource = dataset;
Объект DataReader не поддерживает аналогичного вывода - мы не можем связать объекты таким простым образом:
dataGrid1.DataSource = datareader;
Одним из способов вывода является применение дополнительных объектов DataTable. Объект DataTable предназначен для хранения таблицы, полученной из базы данных (в восьмой лекции мы рассмотрим подробно этот объект). Создайте новое приложение и назовите его "DataReaderToDataGrid". Перетаскиваем на форму элемент управления DataGrid, его свойству Dock устанавливаем значение "Fill". Подключаем пространство имен для работы с базой:
using System.Data.SqlClient;
В классе формы создаем следующие объекты:
SqlConnection conn = null; //Создаем экземпляр FullDataTable, в который будут помещаться данные DataTable FullDataTable = new DataTable(); //Создаем экземпляр ShemaDataTable для получения структуры таблицы из базы данных DataTable ShemaDataTable = new DataTable(); SqlDataReader dataReader; SqlCommand myCommand; //Создаем объект objectRow для получения информации о числе столбцов object[] objectRow;
Основной код помещаем в конструктор формы:
public Form1()
{
InitializeComponent();
try
{
conn = new SqlConnection();
conn.ConnectionString = "integrated security=SSPI;data
source=\".\"; persist security info=False;
initial catalog=BDTur_firm2";
conn.Open();
myCommand = conn.CreateCommand();
myCommand.CommandText = "SELECT * FROM Туристы";
dataReader = myCommand.ExecuteReader();
//Вызываем метод GetSchemaTable, который получает схему таблицы из базы
//и передает ее объекту ShemaDataTable
ShemaDataTable = dataReader.GetSchemaTable();
//Свойство FieldCount возвращает число столбцов для текущей записи.
//Передаем это значение объекту objectRow
objectRow = new object[dataReader.FieldCount];
//Определяем структуру объекта FullDataTable
for(int i =0; i <dataReader.FieldCount; i++)
{
FullDataTable.Columns.Add(ShemaDataTable.Rows[i]
["ColumnName"].ToString(),
((System.Type)ShemaDataTable.Rows[i] ["DataType"]));
}
//Добавляем записи в объект FullDataTable
while(dataReader.Read())
{
dataReader.GetValues(objectRow);
myDataRow = FullDataTable.Rows.Add(objectRow);
}
//Определяем источник данных для элемента dataGrid1
dataGrid1.DataSource = FullDataTable;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
dataReader.Close();
conn.Close();
}
}
Возможно, этот код показался вам сложным. Лучше будет к нему вернуться еще раз после изучения девятой лекции. Запускаем приложение (рис. 6.28):
(рис 6.28) Приложение DataReaderToDataGridВ программном обеспечении к курсу вы найдете приложение Data ReaderToDataGrid (Code\Glava3\ DataReaderToDataGrid).
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.