Книга: Обработка баз данных на Visual Basic®.NET
Отношения между таблицами
Разделы на этой странице:
Отношения между таблицами
Поскольку объект DataSet может содержать несколько таблиц, то вполне естественно, что между ними могут существовать какие-то отношения (по крайней мере, если речь идет о реляционных базах данных). В модели ADO.NET для этого предусмотрен объект DataRelation.
Объект DataRelation устанавливает соответствие между полями в двух таблицах, которые имеют родительско-дочерние отношения или связаны первичным и внешним ключами. Классический пример такого отношения существует между таблицами с данными о клиентах и с данными о заказах, где одна запись клиента может быть связана с несколькими записями его заказов. Запись клиента является родительской, а записи заказов — дочерними. Продолжим обсуждение этой темы на примере родительской таблицы Department и дочерней таблицы Employees, которые находятся в одном объекте DataSet.
Объект DataRelation выполняет две разные функции.
• Позволяет переходить от одной связанной таблицы к другой и обратно, т.е. при работе с родительской записью можно получить доступ к ее дочерним записям, а при работе с дочерней записью — доступ к ее родительской записи.
• Позволяет задавать и поддерживать ссылочную целостность, например каскадные обновления данных в связанных таблицах при выполнении каких-либо изменений в любой из связанных таблиц.
Продолжим работу с упомянутым ранее проектом DataSetCode.
1. Создайте новую кнопку непосредственно под кнопкой Create DataSet, перетаскивая ее из панели элементов управления.
2. В окне свойств Properties укажите значение btnCreateRelations для свойства (Name) и значение Create Relations для свойства Text.
3. Вставьте код, показанный в листинге 5.6.
Листинг 5.6. Код создания и отображения отношений между таблицами
Private Sub btnCreateRelations_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnCreateRelations.Click
Dim As DataRelation
CreateDataSet()
' Создание отношения между таблицами Departments и Employees.
rel = dsEmployeeInfо.Relations.Add(_
"relDepartmentEmployees", _
dsEmployeeInfo.Tables("Departments").Columns("ID"), _
dsEmployeeInfo.Tables("Employees").Columns("DepartmentID"))
DisplayRelations(dsEmployeeInfo)
End Sub
Private Sub DisplayRelations(ByVal ds As DataSet)
Dim rel As DataRelation
' Вывод имен полей созданного отношения.
Me.lstOutput.Items.Add("")
Me.lstOutput.Items.Add("DISPLAY RELATIONS")
For Each rel In ds.Relations
' Вывод имени отношения.
Me.lstOutput.Items.Add("NAME: " & rel.RelationName)
' Вывод имени родительской таблицы и ее поля,
' которое входит в созданное отношение.
Me.IstOutput.Items.Add("PARENT: " & _
rel.ParentTable.ToString & " – " & _
rel.ParentColumns(0).ColumnName)
' Вывод имени дочерней таблицы и ее поля,
' которое входит в созданное отношение.
Me.lstOutput.Items.Add("CHILD: " & _
rel.ChildTable.ToString & " – " & _
rel.ChildColumns(0).ColumnName)
Next
Me.lstOutput.Items.Add("")
End Sub
Сначала нужно создать объект DataRelation. Каждый объект DataSet содержит коллекцию отношений, которая доступна как свойство этого объекта Relations. Это свойство имеет тип DataRelationCollection и поддерживает несколько перегруженных версий метода Add. Версия, использованная в листинге 5.6, принимает три аргумента: имя отношения, ссылку на объект DataColumn в родительской таблице, а также ссылку на объект DataColumn в дочерней таблице. Если отношение между таблицами охватывает более одного поля, то следует использовать другую версию метода Add с аргументами-массивами объектов DataColumn.
Подпрограмма DisplayRelations циклически обходит все отношения свойства Relations объекта DataSet и выводит в текстовом поле имя отношения, имя родительской таблицы и ее поле, которое входит в созданное отношение, а также имя дочерней таблицы и ее поле, которое входит в созданное отношение.
НА ЗАМЕТКУ
Для создания более обобщенной версии подпрограммы DisplayRelations можно было бы вставить код циклического обхода всех полей в свойствах-массивах РаrentColumns и ChildColumns, а не просто отображать их первые элементы.
После компоновки проекта DataSetCode и запуска полученного приложения щелкните на кнопке Create Relations, и в текстовом поле будет выведена информация о вновь созданном отношении между таблицами Employees и Departments.
Кроме коллекции Relations объекта DataSet, которая содержит все отношения, определенные между таблицами объекта DataSet, каждый объект DataTable также содержит две коллекции отношений (т.е. два свойства): ParentRelations и ChildRelations, которые содержат отношения между данным объектом DataTable и связанной с ним другой (дочерней или родительской) таблицей.
После создания отношения между таблицами можно организовать доступ к связанным данным в них. Начните с создания кнопки и вставки кода, приведенного в листинге 5.7.
1. Создайте новую кнопку непосредственно под кнопкой Create Relations, перетаскивая ее из панели элементов управления.
2. В окне свойств Properties укажите значение btnChildRows для свойства (Name) и значение Child Rows для свойства Text.
3. Вставьте код, показанный в листинге 5.7.
Листинг 5.7. Код отображения родительских и дочерних данных из связанных таблиц
Private Sub btnChildRows_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnChildRows.Click
Dim rel As DataRelation CreateDataSet()
AddData()
' Создание отношения между таблицами Departments и Employees
rel = dsEmployeeInfо.Relations.Add("relDepartmentEmployees", _
dsEmployeeInfo.Tables("Departments").Columns("ID"), _
dsEmployeeInfo.Tables("Employees").Columns("DepartmentID"))
DisplayChildRows(dsEmployeeInfo.Tables("Departments"))
End Sub
Private Sub DisplayChidRows(ByVal dt As DataTable)
Dim rel As DataRelation
Dim relatedRows() As DataRow
Dim row As DataRow
Dim col As DataColumn
Dim i As Integer
Dim rowData As String
Me.lstOutput.Items.Add("")
Me.lstOutput.Items.Add("CHILD ROWS")
For Each row In dt.Rows
For Each rel In dt.ChildRelations
Me.lstOutput.Items.Add(_
dt.TableName & ": " & _
rel.ParentColumns(0).ColumnName & _
"= " & row(rel.ParentColumns(0).ToString))
relatedRows = row.GetChildRows(rel)
' Вывод значений записей.
For i = 0 To relatedRows.GetUpperBound(0)
rowData = "****" & _
rel.ChildTable.TableName & ":"
For Each col In rel.ChildTable.Columns
rowData = rowData & " " & _
relatedRows(i)(col.ToString)
Next col
Me.lstOutput.Items.Add(rowData)
Next i
Next rel
Next row
End Sub
Подпрограмма btnChildRows_Click для обработки щелчков на кнопке Child Rows сначала создает объект DataSet и объекты DataTable с помощью подпрограммы CreateDataSet (код которой приведен в листинге 5.1), а затем наполняет их данными с помощью подпрограммы AddData (код которой приведен в листинге 5.2). После этого между таблицами Employees и Departments создается отношение с помощью кода, который приведен в листинге 5.6. Наконец, для вывода данных из записей в текстовом поле формы вызывается подпрограмма DisplayChildRows, которой в качестве аргумента (родительской таблицы) передается таблица Departments.
Подпрограмма DisplayChildRows содержит трижды вложенный цикл для отображения всех полей из каждой связанной дочерней таблицы (в данном случае только одной) для каждой записи родительской таблицы. При этом каждая запись родительской таблицы передается циклу как аргумент, происходит обход всех отношений, определенных в свойстве ChildRelations таблицы, отображается имя таблицы, имя поля в родительской таблице, а также значение поля в текущей записи. Затем вызывается метод GetChildRows с текущим отношением в качестве аргумента и возвращается массив объектов DataRow, содержащих дочерние записи. Для каждой записи отображаются все поля с префиксами в виде четырех звездочек и имени дочерней таблицы.
НА ЗАМЕТКУ
Некоторые версии метода GetChildRows принимают дополнительный аргумент, который указывает на используемую версию возвращаемых записей с помощью членов перечисления DataRowVersion из табл. 5.2. Аналогичные методы предусмотрены для извлечения родительской записи (или нескольких родительских записей) по заданной дочерней записи.
Здесь у читателя может возникнуть вопрос: почему упоминается несколько родительских записей? Разве дочерняя запись может иметь несколько родительских записей? Дело в том, что кроме родительских полей, заданных на основе полей с уникальными значениями, могут создаваться родительские поля на основе полей с повторяющимися значениями. Поэтому в таких случаях вместо одной родительской записи (GetParentRow) приходится извлекать несколько родительских (GetParentRows).
РИС. 5.3. Результаты отображения родительских и дочерних записей из таблиц Employees и Departments
После компоновки проекта DataSetCode и запуска полученного приложения щелкните на кнопке Child ROWS, и в текстовом поле будут выведены значения всех родительских записей из таблицы Employees для каждой родительской записи из таблицы Departments (рис. 5.3).
- Связи между таблицами
- 12.7. Многотабличные базы данных. Отношения между таблицами
- Миграция между различными версиями InterBase
- 3.4. Отношения между классами
- Мост между физической и логической структурой базы данных
- Безопасная работа с внешними таблицами
- 5. Отношения. Типы отношений
- 2. Пример создания базового отношения в записи на псевдокоде
- Распределение функциональных обязанностей между должностями
- Правило 16. Группируйте связанные между собой элементы
- 6.4.2. Передача номенклатурных позиций между ячейками склада
- Как быстро переключаться между двумя пользователями, не закрывая их программ?