Книга: Обработка баз данных на Visual Basic®.NET
Бизнес-ситуация 6.1: комбинация нескольких связанных таблиц
Разделы на этой странице:
Бизнес-ситуация 6.1: комбинация нескольких связанных таблиц
Как уже отмечалось, ни один из перечисленных выше методов указания команд обновления не позволяет обновлять данные сразу в нескольких таблицах, особенно если они связаны родительско-дочерним отношением. Значит ли это, что в модели ADO.NET не поддерживается обработка такой ситуации? Нет, это не так. В данной бизнес-ситуации для доказательства этого утверждения демонстрируются функциональные возможности модели ADO.NET, в частности применение пакета команд SQL для вставки данных из двух таблиц за счет одного обращения к серверу. Итак, программист компании Jones Novelties, Inc. создает форму для отображения и обновления данных о клиентах и их заказах. Для создания такой формы выполните перечисленные ниже действия.
РИС. 6.4. Расположение элементов управления в форме frmCustomersOrders
1. Запустите среду разработки Visual Studio .NET.
2. Создайте новый проект Visual Basic Windows Application.
3. Назовите проект BusinessCase6.
4. Укажите путь к файлам проекта.
5. Увеличьте размер формы Form1 и в окне Properties укажите значение frmCustomersOrders для свойства (Name) и значение Customers and Orders для свойства Text формы Form1.
6. Перетащите в форму кнопку и в окне Properties укажите значение bntFill для ее свойства (Name) и Fill для свойства Text; перетащите в форму кнопку и в окне Properties укажите значение bntUpdate для ее свойства (Name) и значение Update для свойства Text; перетащите в форму сетку данных и в окне Properties укажите значение grdCustomersOrders для ее свойства (Name).
7. Расположите все элементы управления, как показано на рис. 6.4.
В верхней части файла с исходным кодом вставьте следующие строки кода для импорта пространств имен System. Data и System.Data.SqlClient:
Imports System.Data
Imports System.Data.SqlClient
В тело определения класса для формы frmCustomersOrders включите код из листинга 6.7.
Листинг 6.7. Код загрузки и обновления данных сразу в нескольких связанных таблицах
Private ds As DataSet
Private en As New SqlConnection( _
"server=localhost;uid=sa;database=Novelty")
Private Sub btnFill_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnFill.Click
Dim da As New SqlDataAdapter()
grdCustomersOrders.DataSource = Nothing
ds = New DataSet()
' Создание команды SELECT.
da.SelectCommand = New SqlCommand()
da.SelectCommand.Connection = cn
da.SelectCommand.CommandType = CommandType.Text
da.SelectCommand.CommandText = _
"select * from tblCustomer; select * from tblOrder"
' Указание информативных имен для таблиц.
da.TableMappings.Add("Table", "Customers")
da.TableMappings.Add("Table1", "Orders")
' Загрузка данных, da.Fill(ds)
' Создание отношения.
ds.Relations.Add("Customer_Orders", _
ds.Tables("Customers").Columns("ID"), _
ds.Tables("Orders").Columns("CustomerID"))
' Отображение данных.
grdCustomersOrders.DataSource = ds
End Sub
Private Sub btnUpdate_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnUpdate.Click
' Создание адаптеров данных.
Dim daCustomers As New SqlDataAdapter( _
"select * from tblCustomer", en)
Dim daOrders As New SqlDataAdapter( _
"select * from tblOrder", en)
Dim cbCustomers As New SqlCommandBuilder(daCustomers)
Dim cbOrders As New SqlCommandBuilder(daOrders)
Try
' Внесение изменений в таблицы в "правильном"
' порядке (см. далее в тексте).
Dim ChangedTable As New DataTable()
' Удаление записей в дочерней таблице.
ChangedTable = _
ds.Tables("Orders").GetChanges(DataRowState.Deleted)
If Not ChangedTable Is Nothing Then
daOrders.Update(ChangedTable)
End If
' Все измененные записи в родительской таблице.
ChangedTable = ds.Tables("Customers").GetChanges
If Not ChangedTable Is Nothing Then
daCustomers.Update(ChangedTable)
End If
' Новые или измененные записи в дочерней таблице.
ChangedTable = _
ds.Tables("Orders").GetChanges(DataRowState.Added _
Or DataRowState.Modified)
If Not ChangedTable Is Nothing Then
daOrders.Update(ChangedTable)
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Первая подпрограмма btnFill_Click считывает обе таблицы из базы данных посредством одного обращения к базе данных благодаря выполнению пакета команд SQL. В объекте CommandText отдельные команды пакета отделяются точкой с запятой.
Обратите внимание, что предлагаемые по умолчанию имена таблиц Table и Table1 в приведенных ниже строках кода отображаются на более информативные имена Customers и Orders.
' Указание информативных имен для таблиц.
da.TableMappings.Add("Table", "Customers")
da. TableMappings.Add("Table1", "Orders")
НА ЗАМЕТКУ
Более подробно способы отображения таблиц и полей рассматриваются в главе 7, "ADO.NET: дополнительные компоненты".
После вставки данных в набор данных ds между таблицами Customers и Orders создается отношение DataRelation, где Customers является родительской таблицей, a Orders — дочерней. Последняя строка кода в этой подпрограмме связывает набор данных DataSet с сеткой для отображения данных.
Вторая подпрограмма, btnUpdate_Click, вносит в базу данных изменения данных в объектах-таблицах с учетом родительско-дочерних связей между ними. К сожалению, ссылочная целостность данных не поддерживается автоматически, а потому ее нужно организовать вручную. Для этого разработчику необходимо сгруппировать типы изменений, а затем выполнить их в правильном порядке. Для двух таблиц, между которыми существуют родительско-дочерние связи, изменения следует вносить в приведенном ниже порядке.
1. Сначала удалить записи в дочерней таблице.
2. Вставить, обновить и удалить записи в родительской таблице.
3. Вставить и обновить записи в дочерней таблице.
Для получения соответствующих изменений подпрограмма должна вызвать для данной таблицы метод GetChanges с фильтром состояния записи. Каждый вызов метода GetChanges возвращает объект DataTable только с измененными записями и заданным состоянием. Если таких записей нет, то возвращается значение Nothing. Если есть хотя бы одна измененная строка с заданным состоянием, то для фактического обновления базы данных вызывается метод Update объекта DataAdapter. Код этой подпрограммы окружен блоком операторов Try-Catch для обработки исключительных ситуаций, которые могут возникнуть в процессе обновления базы данных.
Скомпонуйте проект BusinessCase6 и проверьте полученное приложение, выполнив перечисленные ниже действия.
1. Запустите полученное приложение BusinessCase6 и щелкните на кнопке Fill. Это приведет к вставке данных в объект DataSet из базы данных Novelty. Однако строка кода
grdCustomersOrders.DataSource = ds
связывает с сеткой весь объект DataSet, а не какую-то одну таблицу DataTable. Поэтому сетка содержит раскрывающийся список таблиц возле кнопки с изображением знака "плюс", как показано на рис. 6.5.
РИС. 6.5. Исходный вид формы frmCustomersOrders после вставки данных в объект DataSet
2. Щелкните на пиктограмме с изображением знака "плюс", раскроется список ссылок на две таблицы объекта DataSet.
3. Щелкните на ссылке Customers, и в сетке будут отображены данные из таблицы tblCustomers. Обратите внимание, что каждая строка в таблице tblCustomers имеет кнопки с изображением знака "плюс" с левой стороны, что означает связь этой таблицы с другими таблицами. После щелчка на такой кнопке раскрывается список объектов DataRelations для данной таблицы. В нашем примере имеется только одна ссылка для отношения Customer_Orders, созданного в подпрограмме btnFillClick (рис. 6.6).
РИС. 6.6. Ссылка Customer_Orders для первой записи из таблицы Customers
4. Щелкните на ссылке Customer_Orders в первой записи. На основании определения отношения Customer_Orders будут вставлены и отображены записи из таблицы Orders, которые относятся к текущей записи из таблицы Customers.
НА ЗАМЕТКУ
При переходах между разными таблицами и отношениями можно всегда вернуться исходному положению в используя кнопку Navigates back to the parent rows (Обратный переход к родительским записям) с изображением стрелки в правом верхнем углу формы.
Теперь с помощью этой формы пользователи могут просматривать имеющиеся и вводить новые данные. При вводе новой дочерней записи значение 1 в поле указывается автоматически, потому что сетка способна определить его в связанной записи из родительской таблицы. Продолжим и добавим значения для полей OrderDate и Amount. При этом не нужно задавать значение для поля ID, потому что это идентификационное поле, которому значение присваивается автоматически.
5. Щелкните на кнопке Update для выполнения подпрограммы btnUpdate_Click из листинга 6.7, которая вносит указанные изменения данных в базу данных.
6. Чтобы проверить корректность внесенных изменений, щелкните на кнопке Fill для повторной загрузки информации из базы данных в объект DataSet и сетку. Откройте первую запись таблицы Customers и найдите ее дочерние записи. Убедитесь в том, что среди них находится введенная вами дочерняя запись.
Попробуйте внести дополнительные изменения в базу данных вставляя, удаляя и изменяя записи в обеих таблицах и проверяя выполнение обновлений.
НА ЗАМЕТКУ
Успешное удаление записи из родительской таблицы Customer вместе с ее дочерними записями из таблицы Orders возможно благодаря заданному по умолчанию ограничению ForeignKeyConstraint для отношения Customer_Orders, которое заключается в каскадном обновлении (удалении) данных в родительской и дочерней таблицах.
- Когда нужен постскриптум в бизнес-тексте?
- Глава 4 Методы и техники бизнес-тренинга
- Глава 7 Чего нужно опасаться при моделировании бизнес-процессов. Проектные риски моделирования бизнеспроцессов
- Безопасная работа с внешними таблицами
- Одновременный запуск нескольких копий сервера (multi-instancing)
- Модификация системных таблиц
- Безопасность временных таблиц
- Безопасность внешних таблиц. Параметр EXTERNAL FILE DIRECTORY
- 6.5 Хост в таблице маршрутизации IP
- 6.3. Содержание оценки бизнес-тренинга
- Глава 10 Информационная безопасность бизнеса
- 4. Стадии бизнес-процесса взаимодействия с клиентами