Книга: Обработка баз данных на 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).

Оглавление книги


Генерация: 0.941. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз