- •Содержание
- •Введение
- •Цель лабораторной работы
- •Задачи лабораторной работы
- •Задание
- •Методика выполнения задания
- •Этап 1. Анализ требований к приложению и проектирование интерфейса
- •Информационная модель базы данных
- •Этап 2. Создание проекта
- •Этап 3. Подключение к базе данных
- •Выбор объектов базы данных
- •Структура главного меню
- •Этап 4. Создание представлений данных
- •Свойства TableAdapter
- •Этап 5. Создание запросов с параметрами
- •Ввод sql запроса
- •Этап 6. Отображение таблиц в приложении
- •Способ 1
- •Выбор источника данных
- •Способ 2
- •Панель инструментов BindingNavigator
- •Этап 7. Взаимодействие двух связанных таблиц в приложении
- •Этап 8. Связывание полей таблицы с элементами управления
- •Компонент NumericUpDown
- •Компонент DateTimePicker
- •Компонент ComboBox
- •Этап 9. Поиск (фильтрация данных)
- •Этап 10. Проверка введённых данных. Обработка ошибок
- •Этап 11. Создание форм справочников
- •Справочник клиентов Этап 12. Создание отчётов
- •Редактирование выражения для поля Text Box
- •Связь компонента ReportViewer с отчётом.
- •Форма с отчётом
- •Критерии результативности выполнения лабораторной работы
- •Контрольные вопросы
- •Список литературы
Этап 10. Проверка введённых данных. Обработка ошибок
При работе с приложением пользователь может допускать различные ошибки, например, не заполнять обязательные поля, вставлять данные в неправильном формате или нарушающие логическую целостность базы данных и т.д.
В связи с этим при разработке приложения важно предусмотреть обработку таких ситуаций. При этом пользователь должен получать понятное сообщение об ошибке с указанием способа ее устранения.
Рассмотрим некоторые ошибки, которые может допустить пользователь на примере таблицы со списком покупок «Purchases».
Как видно из информационной модели, представленной на этапе 1, первичный ключ таблицы состоит из двух полей − номера заказа и номера накладной. Это значит, что в рамках одного заказа не может быть двух покупок, совершённых по одной накладной. Кроме того, поле quantity является обязательным и его значение не должно превышать количества товара, доступного на складе на момент совершения покупки.
Рассмотрим все ошибки по отдельности. Найдём в исходном коде место, в котором предполагается написать код, отвечающий за сохранение изменений в базу данных (это может быть как обработчик события Click ранее помещённой на форме кнопки «Сохранить», так и код кнопки сохранения на панели BindingNavigator).
Для начала проверим, заполнены ли все обязательные поля, на которые было наложено ограничение целостности not null, unique или primary key.
this.Validate();
DataRowView curPur = (DataRowView)purchasesBindingSource.Current;
if (Convert.IsDBNull(curPur["id_invoice"]))
{
MessageBox.Show("Не выбрана накладная!","Не указаны данные",MessageBoxButtons.OK,MessageBoxIcon.Warning);
this.comboInvoice.Focus();
return;
}
В приведённом фрагменте кода проверяется поле «id_invoice» (номер накладной) на равенство неопределенному значению null. Если проверка выполняется, выводится сообщение об ошибке, фокусируется выпадающий список накладных и выполняется возврат в точку вызова функции.
Аналогичным образом выполняется проверка и для других полей:
if (Convert.IsDBNull(curPur["quantity"]))
{
MessageBox.Show("Не указано количество!", "Не указаны данные", MessageBoxButtons.OK, MessageBoxIcon.Warning);
this.numQuantity.Focus();
return;
}
Следующая ошибка, которая может возникнуть − это выбор накладной, по которой уже была совершена покупка в данном заказе. Поскольку предполагается, что из таблицы purchases с помощью параметрического запроса (см. этап 5) отобраны только покупки, соответствующие выбранному заказу из таблицы «Orders», задача проверки на корректность ввода сводится к поиску существующей записи о покупке по ключу «id_invoices» (номер накладной).
int inv = Convert.ToInt32(curPur["id_invoice"]);
int p = this.purchasesBindingSource.Find("id_invoice", inv);
if (p >= 0)
{
MessageBox.Show("В одном заказе не может быть двух покупок по одной накладной!", "Данные указаны некорректно",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
this.comboInvoice.Focus();
return;
}
В приведённом коде для поиска записи по ключу используется метод Find объекта purchasesBindingSource, который возвращает номер первой найденной записи. Если метод возвращает неотрицательное число, это значит, что запись с заданным значением ключа «id_invoice» была найдена и добавить ещё одну запись с тем же значением невозможно.
Даже в том случае, если все ограничения целостности удовлетворены, пользователь может заказать товар в количестве, превышающем наличие на складе. В нашем случае эта проверка реализована на сервере в триггере для таблицы «Purchases». В коде триггера сообщение об ошибке выдаётся следующим образом:
RAISERROR('Превышено количество доступного товара для выбранной накладной.',16,1)
Задача приложения − перехватить и вывести это сообщение. Поскольку это исключительная ситуация, для этого можно использовать блок try…catch:
this.purchasesBindingSource.EndEdit();
try
{
this.purchasesTableAdapter.Update(this.shopDataSet.purchases);
}
catch (SqlException se)
{
MessageBox.Show(se.Message, "Ошибка сохранения", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
В приведённом фрагменте кода в случае возникновения исключительных ситуаций типа SqlException при попытке сохранения изменений в таблицу «Purchases» выводится сообщение об ошибке, заданное на сервере (в нашем случае функцией RAISERROR()).
Приведённой конструкцией можно обрабатывать любые ошибки, выдаваемые сервером, например, о нарушении ограничения целостности при попытке удалить запись из родительской таблицы, на которую ссылается дочерняя таблица.
Для того чтобы приложение имело возможность обрабатывать исключения вида SqlException, необходимо в начале кода соответствующего модуля подключить пространство имён:
using System.Data.SqlClient;
Обратите внимание, что после сохранения изменений в таблице «Purchases» имеет смысл её обновить методом FillByOrder() объекта purchasesTableAdapter, поскольку стоимость покупки (поле cost) также вычисляется в триггере на сервере.
