ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
В следующем примере использования объекта чтения данных применяется метод Read() для определения момента достижения конца записей (тогда возвращаемое значение оказывается равным false). Для каждой поступающей записи индексатору типа дается указание напечатать информацию о марке автомобиля, его названии и цвете. Также обратите внимание на то, что сразу же после завершении обработки записей вызывается метод Close(), чтобы освободить объект соединения.
static void Main(string[] args) {
…
// Получение объекта чтения данных в стиле ExecuteReader().
SqlDataReader myDataReader;
myDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
// Цикл по результирующему набору.
while(myDataReader.Read()) {
Console.WriteLine("-› Марка – {0}, название – {1}, цвет – {2}",
myDataReader["Make"].ToString().Trim(),
myDataReader["PetName"].ToString().Trim(),
myDataReader["Color"]. ToString().Trim());
}
myDataReader.Close();
ShowConnectionStatus(on);
}
Замечание. Обрезка строковых данных здесь используется только для того, чтобы удалить пробелы в конце полей базы данных, и это никак не связано с ADO.NET.
Индексатор объекта чтения данных перегружен, чтобы ему можно было передать либо строку (представляющую имя столбца), либо целое число (соответствующее порядковому номеру столбца). Поэтому вы можете немного "подчистить" соответствующий фрагмент программы (избавившись от необходимости печатания имен) и использовать вариант, показанный ниже (обратите внимание на использование свойства FieldCount).
while (myDataReader.Read()) {
Console.WriteLine("***** Запись *****");
for (int i = 0; i ‹ myDataReader.FieldCount; i++) {
Console.WriteLine("{0} = {1} ", myDataReader.GetName(i), myDataReader.GetValue(i).ToString().Trim());
}
Console.WriteLine();
}
После компиляции и запуска этого проекта вы должны увидеть список всех автомобилей из таблицы Inventory базы данных Cars (рис. 22.7).
Рис. 22.7. Объекты чтения данных
Получение множества наборов результатов с помощью объектов чтения данных
Объекты чтения данных могут получать от одного объекта команды множество наборов результатов. Например, чтобы получить все строки таблицы Inventory и все строки таблицы Customers, можно указать оба соответствующих SQL-оператора, используя в качестве разделителя точку с запятой.
string theSQL = "Select * From Inventory:Select * "from Customers";
Получив объект чтения данных, можно переходить от одного результирующего набора к другому с помощью метода NextResult(). При этом возвращение к первому набору происходит автоматически. Поэтому, чтобы прочитать строки каждой таблицы, можно построить следующую итерационную конструкцию.
do {
while (myDataReader.Read()) {
// Чтение информации текущего набора результатов.
}
} while (myDataReader.NextResult());
Теперь вы должны знать больше о возможностях объектов чтения данных. Эта объекты предлагают и другие возможности, о которых здесь не упоминалось (например, выполнение скалярных и однострочных запросов). Соответствующие подробности можно найти в документации .NET Framework 2.0 SDK.
Исходный код. Проект CarsDataReader размещен в подкаталоге, соответствующем главе 22.
Изменение содержимого таблиц с помощью объектов команд
Вы только что убедились, что метод ExecuteReader() извлекает объект чтения данных, позволяющий проверить результаты выполнения SQL-оператора Select в однонаправленном и доступном только для чтения потоке. Но если вы хотите применить SQL-команду, в результате которой должна произойти модификация таблицы, вы должны вызвать метод ExecuteNonQuery() соответствующего объекта команды. Этот метод выполняет вставки, обновления и. удаления в соответствии с форматом соответствующей команды.
Чтобы проиллюстрировать возможность модификации существующей базы данных с помощью вызова ExecuteNonQuery(), мы с вами построим новое консольное приложение (CarsInventoryUpdater), предоставляющее пользователю возможность изменения данных таблицы Inventory базы данных Cars. Как и в других примерах, метод Main() здесь отвечает за получение от пользователя инструкций по поводу выполнения конкретных действий, что программно реализуется с помощью оператора switch. Программа разрешает пользователю ввести следующие команды:
• I - вставить новую запись в таблицу Inventory;
• U - обновить существующую запись в таблице Inventory;
• D – удалить существующую запись из таблицы Inventory;
• L – вывести информацию об имеющемся наборе автомобилей, используя объект чтения данных;
• S – показать эти варианты выбора пользователю;
• Q - выйти из программы.
Каждый возможный вариант обрабатывается своим уникальным статическим методом в рамках класса Program. Для полной ясности вот реализация Main(), которая, как кажется, не требует никаких дополнительных комментариев.
static void Main(string[] args) {
Console.WriteLine ("***** Модификатор Inventory для Car *****");
bool userDone = false;
string userCommand = "";
SqlConnection cn = new SqlConnection();
cn.ConnectionString = "uid=sa;pwd=;Initial Catalog=Cars;" +
"Data Source=(local);Connect Timeout=30";
cn.Open();
ShowInstructions();
do {
Console.Write("Введите команду: ");
userCommand = Console.ReadLine();
Console.WriteLine();
switch (userCommand.ToUpper()) {
case "I":
InsertNewCar(cn);
break;
case "U":
UpdateCarPetName(cn);
break;
case "D":
DeleteCar(cn);
break;
case "L":
ListInventory(cn);
break;
case "S":
ShowInstructions();
break;
case "Q":
userDone = true;
break;
default:
Console.WriteLine("Некорректные данные! Введите другие");
break;
}
} while (!userDone);
cn.Close();
}
Метод ShowInstructions() делает то, что и следует ожидать.
private static void ShowInstructions() {
Console.WriteLine();
Console.WriteLine("I: добавление новой машины.");
Console.WriteLine("U: модификация имеющейся машины.");
Console.WriteLine("D: удаление имеющейся машины.");
Console.WriteLine("L: список наличных машин.");
Console.WriteLine("S: вывод инструкций.");
Console.WriteLine(''Q: выход из программы.");
}
Как уже упоминалось, метод ListInventorу() печатает строки таблицы Inventory с помощью объекта чтения данных (соответствующий программный код аналогичен программному коду предыдущего примера CarsDataReader).
private static void ListInventory(SqlConnection cn) {
string strSQL = "Select * From Inventory";
SqlCommand myCommand = new SqlCommand(strSQL, cn);
SqlDataReader myDataReader;
myDataReader = myCommand.ExecuteReader();
while (myDataReader.Read()) {
for (int i = 0; i ‹ myDataReader.FieldCount; i++) {
Console.Write("{0} = {1}"; myDataReader.GetNаmе(i), myDataReader.GetValue(i).ToString().Trim());
}
Console.WriteLine();
}
myDataReader.Close();
}
Итак, текстовый интерфейс пользователя готов, и мы можем теперь перейти к более интересным вещам.
Вставка новых записей
Для вставки новой записи в таблицу Inventory нужно (на основе пользовательского ввода) создать SQL-оператор вставки и вызвать ExecuteNonQuery(). Чтобы не загромождать программный код, здесь из него удалена необходимая программная логика try/catch, которая присутствует в загружаемом варианте программного кода примеров для этой книги.
private static void InsertNewCar(SqlConnection cn) {
// Сбор информации о новой машине.
Console.Write("Введите номер машины: ");
int newCarID = int.Parse(Console.ReadLine());
Console.Write("Введите марку: ");
string newCarMake = Console.ReadLine();
Console.Write("Введите цвет: ");
string newCarColor = Console.ReadLine();
Console.Write("Введите название: ");
string newCarPetName = Console.ReadLine();
// Создание и выполнение оператора SQL.
string sql = string.Format("Insert Into Inventory" +
"(CarID, Make, Color, PetName) Values" +
"({0}', '{1}', '{2}', '{3}')",
newCarID, newCarMake, newCarColor, newCarPetName);
SqlCommand cmd = new SqlCommand(sql, cn);
cmd.ExecuteNonQuery();
}
Замечание. Вы, возможно, знаете, что построение SQL-операторов с помощью конкатенации строк достаточно рискованно с точки зрения безопасности (вспомните о возможных атаках SQL-инъекции). Здесь этот подход используется только для простоты, поскольку, конечно же, предпочтительнее строить текст команд с помощью параметризованных запросов, обсуждение которых предполагается немного позже.