Практическая работа по теме 2. "Программирование в средах современных информационных систем"

advertisement
Практическая работа по теме 2.
"Программирование в средах современных
информационных систем"
Компоненты объекта DataSet. Определение метаданных для объекта DataTable.
Вставка и удаление данных в DataTable. Доступ к данным с помощью объекта
DataTable. Поиск, фильтрация и сортировка записей. Отношения между
таблицами. Ограничения целостности данных. Визуальное программирование
объекта DataSet.
Оглавление
Задание
Задание
Задание
Задание
Задание
Задание
Задание
1.
2.
3.
4.
5.
6.
7.
Определение метаданных для объекта DataTable
Вставка и удаление данных в объекте DataTable
Доступ к данным с помощью объекта DataTable
Поиск, фильтрация и сортировка записей
Отношения между таблицами
Ограничения целостности данных
Визуальное программирование объекта DataSet
Задание 1. Определение метаданных для объекта
DataTable
Цель
Научиться программировать определение метаданных для объекта DataTable.
Решение
Написать код определения схемы объекта DataTable, указывая необходимые
свойства ReadOnly, Unique, AllowDbNull, AutoIncrement для объектов DataColumn.
Обсуждение
Объект
DataSet
является
ключевым
объектом
ADO.NET
и
служит
универсальным контейнером данных, независимо от используемого источника
данных. Объект DataSet и связанные с ним подчиненные объекты предлагают
реляционное представление данных, хотя объект DataSet также способен
загружать и сохранять свои данные в формате XML (Extensible Markup Language расширяемый язык разметки).
Данные в объекте DataSet организованы в одной или нескольких объектах
DataTable. Каждый объект DataTable существует независимо от источника данных,
то есть он всегда отключен от источника данных, как и DataSet. Объекты
DataTable всего лишь хранят таблицы данных и предлагают возможности
манипулирования, передачи или связывания их с элементами управления
пользовательского интерфейса.
На рис.2.1 показана схема взаимодействия объекта DataSet и связанных с ним
подчиненных объектов. Объекты DataTable содержит коллекции объектов
DataRow, DataColumn и Constraint, а также коллекции объектов DataRelation,
связанные с другими родительскими и дочерними объектами. Существует три
способа ввода данных в таблицы DataTable объекта DataSet.
Рис. 2.1. Схема взаимодействия объекта DataSet с подчиненными объектами

Программирование определений метаданных и прямая вставка
данных.

Использование объекта DataAdapter для создания запроса по
отношению к источнику данных.
 Загрузка XML-документа.
В этой практической работе остановимся на способе программирования
структуры и прямого ввода данных в объекты DataTable, так как необходимо
научиться работать с объектом DataSet, понять его устройство, возможности и
особенности. Два других способа будут рассмотрены в следующих практикумах.
1. Для изучения основных принципов технологии программирования схемы
DataTable
создайте
Windows-форму
в
вашем
проекте.
2.
В
свойстве
Text
формы
укажите
DataSet.
3. Добавьте в форму элементы управления.
Форма должна включать командную кнопку "Create DataSet" и поле со списком
ListBox для просмотра результатов выполнения программы (рис. 2.2). Щелчок по
командной кнопке должен выполнять действия по созданию объекта DataSet,
определения схемы объектов DataTable, входящих в структуру DataSet.
4. Код процедуры приведен ниже, скопируйте его в свой проект.
Рис. 2.2. Интерфейс приложения для исследования объекта DataSet
Private dsE As DataSet ' Создаем объект класса
DataSet
Private
Sub
Button1_Click(ByVal
sender
As
System.Object, ByVal e As System.EventArgs) Handles
Button1.Click
CreateDataSet()
'Это процедура создания объектов DataSet и
DataTable,
ее
код
приведен
ниже
AddData()
'Это процедура вставки данных в объекты DataTable
DisplayDataset(dsE)
'Это процедура просмотра данных в объектах
DataTable,
ее
код
приведен
ниже
End Sub
5. Не забудьте в верхней части кода проекта описать импортирование
пространств имен для доступа к классам
System.Data.
Imports System.Data
6. Теперь рассмотрим процесс создания схемы объектов DataTable, из которых
и
состоит
объект
DataSet.
Пусть наше хранилище (DataSet) содержит две таблицы Employees (Сотрудники)
и Departments (Отделы).
Private Sub CreateDataSet()
7. Создание объекта класса DataSet
dsE
=
New
'Создание
таблицы
Dim
dtEmp
As
DataTable
DataTable("Employees")
dtEmp.CaseSensitive = False
DataSet
DataTable
=
New
Свойство таблицы CaseSensitive определяет, будут ли операции сортировки,
поиска и фильтрации выполняться с учетом регистра символов. По умолчанию
значение этого свойства определяется как значение свойства CaseSensitivity
родительского объекта DataSet или принимается равным False, если объект
DataTable создан независимо от объекта DataSet.
Свойство CaseSensitivity применяется только для данных объекта DataTable и
не влияет на имена самих объектов DataTable. Например, объект DataSet может
иметь две таблицы с именами Employees и employees. Для работы с ними надо
точно указывать имя таблицы с соблюдением регистра, это разные объекты. Но
если имеется только одна таблица Employees, то ее имя можно вводить без
соблюдения регистра - она одна.
8. Создадим в таблице столбцы
dtEmp.Columns.Add("FirstName",
Type.GetType("System.String"))
dtEmp.Columns.Add("LastName",
Type.GetType("System.String"))
dtEmp.Columns.Add("DepartmentID",
Type.GetType("System.Int32"))
Обратите внимание на тот факт, что при описании структуры полей таблицы
указываются .NET совместимые типы данных, а не используемые в базе данных
типы. При отсутствии типа данных для него по умолчанию принимается строковый
тип.
9. Требуется определить первичные ключи таблицы Employees.
Это можно сделать с помощью присвоения одного или нескольких полей
свойству PrimaryKey таблицы. Даже если первичный ключ создан на основе
единственного поля, свойство PrimaryKey таблицы является массивом объектов
DataColumn.
В приведенных ниже строках кода первичный ключ таблицы Employees
создается на основе двух столбцов FirstName и LastName.
Dim
pk(1)
pk(0)
=
pk(1)
=
dtEmp.PrimaryKey = pk
As
DataColumn
dtEmp.Columns("FirstName")
dtEmp.Columns("LastName")
При создании первичного ключа с помощью свойства PrimaryKey для объекта
DataTable на основе одного поля для свойства AllowDbNull этого поля
автоматически задается значение False, а для свойства Unique - значение True. А
если первичный ключ создан на основе нескольких полей, то только для свойства
AllowDBNull этих полей автоматически задается значение False.
Добавим
DataTable
dsE.Tables.Add(dtEmp)
в
DataSet
10. Рассмотрим создание таблицы перегруженным конструктором
Dim
dtDep
As
dtDep
=
New
dtDep.TableName
=
dtDep.MinimumCapacity = 5
DataTable
DataTable
"Departments"
11. Для свойства MinimumCapacity задается значение 5 (по умолчанию 25), то
есть экземпляр объекта DataTable создается уже с пятью записями.
dtDep.CaseSensitive = False
12. Создание столбцов таблицы перегруженным конструктором.
Dim
newColumn
As
New
DataColumn
With
newColumn
.ColumnName
=
"ID"
.DataType
=
Type.GetType("System.Int32")
.ReadOnly
=
True
.Unique
=
True
.AutoIncrement
=
True
End
With
dtDep.Columns.Add(newColumn)
13. Перед добавлением полей в коллекцию Columns для них задаются значения
необходимых свойств (ReadOnly, Unique, AllowDbNull, AutoIncrement).
Присвоение свойству ReadOnly значения True указывает на то, что значение
поля нельзя изменить.
Присвоение свойству Unique значения True указывает на то, что значение
данного поля во всех записях таблицы должно быть уникальным. Это свойство
реализуется с помощью автоматического создания ограничения UniqueConstraint
для данного поля . Далее этот процесс повторяется необходимое количество раз.
newColumn
=
New
DataColumn
With
newColumn
.ColumnName
=
"DepartmentName"
.DataType
=
Type.GetType("System.String")
.Unique
=
True
.AutoIncrement
=
False
End
With
dtDep.Columns.Add(newColumn)
Dim
pk1(0)
As
DataColumn
pk1(0)
=
dtDep.Columns("ID")
dtDep.PrimaryKey
=
pk1
dsE.Tables.Add(dtDep)
End Sub
Самостоятельно
Запрограммируйте
определение
метаданных
для
объекта
DataSet,
включающего таблицы модели Dogovor. Модель состоит из четырех таблиц:
Dogovor, Pocupatel, Tovar и Post. Структура таблиц представлена на рис.2.3.
Рис. 2.3. Структура таблиц модели Dogovor
Задание 2. Вставка и удаление данных в объекте
DataTable
Цель
Научиться программировать непосредственный (прямой) ввод данных в объект
DataTable.
Решение
Написать код вставки записей в объект DataTable, создавая экземпляры
объекта DataRow для нужной таблицы с помощью метода NewRow.
Обсуждение
После определения объекта DataTable и его схемы можно начинать ввод
данных. Ниже приводится код вставки записей в таблицы Departments и
Employees. Технологию ввода записей можно описать следующими шагами:
 Сначала создается новый экземпляр объекта DataRow для нужной
таблицы с помощью метода NewRow.
 Затем присваиваются значения полям этой записи.
 После этого запись включается в коллекцию записей Rows таблицы с
помощью метода Add свойства Rows таблицы.
1. Добавьте следующий код в свой проект.
Private
Sub
AddData()
Dim dtDep As DataTable = dsE.Tables("Departments")
Dim dtEmp As DataTable = dsE.Tables("Employees")
2. Вставка записей в таблицу Departments
Dim
rowDep
rowDep
=
rowDep("ID")
rowDep("DepartmentName")
As
=
=
DataRow
dtDep.NewRow
22
"Отдел
сбыта"
dtDep.Rows.Add(rowDep)
rowDep
=
rowDep("ID")
rowDep("DepartmentName")
dtDep.Rows.Add(rowDep)
dtDep.NewRow
=
33
= "Отдел рекламы"
3. Вставка записей в таблицу Employees
Dim
rowEmp
rowEmp
=
rowEmp("FirstName")
rowEmp("LastName")
rowEmp("DepartmentID")
dtEmp.Rows.Add(rowEmp)
rowEmp
=
rowEmp("FirstName")
rowEmp("LastName")
rowEmp("DepartmentID")
dtEmp.Rows.Add(rowEmp)
End Sub
As
=
=
=
=
DataRow
dtEmp.NewRow
"Волнушкин"
"Владимир"
=
22
dtEmp.NewRow
"Белогруздев"
"Григорий"
=
33
Строки можно не только вставлять, но и удалять целиком. Удаление записи
основано на методах Remove, RemoveAt объекта DataRowCollection (то есть
свойства Rows объекта DataTable). Эти методы полностью удаляет запись из
коллекции.
Еще один способ удаления записи основан на методе Delete объекта DataRow.
Этот метод отмечает запись для удаления, которое на самом деле произойдет
только после вызова метода AcceptChanges. После вызова метода Remove все
указанные записи будут удалены необратимо, даже если после этого вызвать
метод RejectChanges.
Стоит сказать о методах AcceptChanges и RejectChanges, которые фиксируют
или наоборот, откатывают последние изменения в классах DataTable, DataSet и
DataRow. Эти методы актуальны при работе с подключением объекта DataSet к
источнику данных. Сейчас мы вводим информацию напрямую в объект DataSet, не
связанный ни с каким источником, поэтому в нашем случае эти методы не имеют
конкретного применения. Но в реальных условиях, когда DataSet заполняется при
подключении к конкретному источнику данных (например, базе данных SQL
Server) эти методы имеют большое значение при редактировании данных и
последующем внесении правок в исходную базу данных .
Практическое использование методов Delete и Remove рассмотрим в задании 4,
когда научимся искать нужную нам запись или массив записей.
Самостоятельно
Напишите код вставки данных в таблицы модели Dogovor.
Задание 3. Доступ к данным с помощью объекта
DataTable
Цель
Написать код отображения данных в объектах DataTable.
Решение
Применить индексы или циклический обход всех элементов коллекций Rows и
Columns для отображения содержимого ранее созданных таблиц.
Обсуждение
Поскольку объект DataSet и содержащийся в нем объект DataTable всегда
наполнены данными и не подключены к источнику данных, метод доступа к
записям имеет свои особенности в сравнении с другими моделями доступа к
данным (например, ODBC, DAO или RDO).
Поскольку все данные доступны одновременно, в модели ADO.NET не
существует понятия "текущая запись". Поэтому нет никаких свойств или методов
для перемещения от одной записи к другой. Каждый объект DataTable имеет
свойство Rows, которое является набором объектов DataRow. Доступ к отдельному
объекту осуществляется с помощью индекса или оператора For Each. Таким
образом, в модели ADO.NET предлагается более простой и эффективный способ
доступа и перемещения, аналогичный доступу к элементам массива.
В коде, приведенном ниже, показано как отображается содержимое ранее
созданных таблиц с загруженными в них данными. В данном случае применяется
циклический обход всех элементов коллекции, то есть коллекций Rows и Columns,
для отображения содержимого таблицы Employees индексы для отображения
содержимого таблицы Departments.
Private
Sub
DisplayDataset()
Циклический обход всех элементов Rows и Columns. Оператор For Each
Dim
dr
As
DataRow
Dim
dc
As
DataColumn
ListBox1.Items.Add("DISPLAY
DATASET")
ListBox1.Items.Add("===============")
For
Each
dr
In
dsE.Tables("Employees").Rows
For
Each
dc
In
dsE.Tables("Employees").Columns
ListBox1.Items.Add(dc.ColumnName
&
":"
&
dr(dc))
Next
ListBox1.Items.Add("---------------")
Next
ListBox1.Items.Add("")
Использование
индексов
для
организации
цикла
обхода
Dim
row
As
Integer
Dim
col
As
Integer
For
row
=
0
To
dsE.Tables("Departments").Rows.Count
1
For col = 0 To dsE.Tables("Departments").Columns.Count - 1
ListBox1.Items.Add(dsE.Tables("Departments").Columns(col).ColumnName
&
":"
&
dsE.Tables("Departments").Rows(row)(col))
Next
col
ListBox1.Items.Add("----------------------")
Next
row
End Sub
1. Попробуем создать процедуру общего типа для обхода не только записей и
полей, но и таблиц объекта DataSet.
Текст процедуры предлагается ниже, обратите внимание на входной параметр
процедуры - это отображаемый объект DataSet, то есть при вызове процедуры вы
должны передать ей в качестве входного параметра имя объекта DataSet,
содержимое которого вы хотите отобразить.
Private
Sub
DisplayDataSet(ByVal
ds
As
DataSet)
'Общая процедура для отображения содержимого объекта
DataSet
Отображаемый объект DataSet передается как параметр
Dim
dt
As
DataTable
Dim
dr
As
DataRow
Dim
dc
As
DataColumn
ListBox1.Items.Add("DISPLAY
DATASET")
ListBox1.Items.Add("===============")
For
Each
dt
In
ds.Tables
ListBox1.Items.Add("")
ListBox1.Items.Add("TABLE:
"
&
dt.TableName)
ListBox1.Items.Add("========================")
For
Each
dr
In
dt.Rows
For
Each
dc
In
dt.Columns
ListBox1.Items.Add(dc.ColumnName
&
":"
&
dr(dc))
Next
dc
ListBox1.Items.Add("--------------------------")
Next
dr
Next
dt
End Sub
2. Теперь мы можем запустить полученное приложение, щелкнув по кнопке
Create DataSet.
В результате должен быть создан объект DataSet, наполнен таблицами и
данными, которые затем отображаются в ListBox (рис. 2.4).
Рис. 2.4. Результат создания объекта DataSet с таблицами Employees и Departments,
наполнения их данными и последующего отображения
Самостоятельно
Используя разработанную процедуру для отображения
выполните отображение таблиц вашей модели Dogovor.
объекта
DataSet,
Задание 4. Поиск, фильтрация и сортировка записей
Цель
Научиться работать с указанными записями объекта DataSet.
Решение
Использовать методы Find и Select, а также состояние и версии записей.
Обсуждение
Обновление данных в объекте DataSet можно организовать с помощью
следующего кода доступа к нужной записи: dtEmp.Rows(2)("DepartmentID") = 22
С практической стороны этот способ не совсем удачен (нужно знать номер
записи), более эффективный и безопасный способ основан на поиске нужной
строки (или нескольких строк). Рассмотрим другие способы доступа к данным.
Метод Find принадлежит свойству DataRowCollection объекта DataTable,
который используется для поиска и возвращения единственной строки, указанной
с помощью значения первичного ключа таблицы.
Dim
r
r = dtDep.Rows.Find("11")
As
DataRow
Здесь переменной r присваивается объект DataRow с указанным значением
первичного ключа или значение Nothing, если такая запись не будет найдена.
Теперь мы умеем искать нужную запись, попробуем удалять эту запись из
набора записей методом Remove. Пример поиска записи по ключевому полю с
последующим ее удалением приведен ниже, результат поиска и удаления показан
на рис. 2.5.
1. Добавьте в проект кнопку Find и программный код для нее.
Private
Sub
Button2_Click(ByVal
sender
As
System.Object, ByVal e As System.EventArgs) Handles
Button2.Click
Dim dtDep As DataTable = dsE.Tables("Departments")
Dim dtEmp As DataTable = dsE.Tables("Employees")
Dim
r
As
DataRow
r
=
dtDep.Rows.Find("11")
MsgBox(r.Item("ID")
&
"
отделэто
"
&
r.Item("DepartmentName"))
dtDep.Rows.Remove(r)
r
=
dtDep.Rows.Find("11")
DisplayDataset()
End Sub
Если первичный ключ таблицы основан на нескольких полях, то
соответствующие значения первичного ключа перелаются в виде элементов
массива (типа Object) методу Find.
Dim
d(1)
As
Object
d(0)
=
"Волнушкин"
d(1)
=
"Владимир"
r
=
dtEmp.Rows.Find(d)
MsgBox(r.Item("DepartmentID"))
Метод Select объекта DataTable возвращает массив объектов DataRow.
Возвращаемые строки могут соответствовать критерию фильтрования, порядку
сортировки
и/или
спецификации
состояния
(объект
DataViewRowState
пространства имен System.Data).
2. Добавьте в форму вашего проекта еще одну кнопку Select и попробуйте
различные варианты поиска: с сортировкой и без нее, с фильтрацией по
различным критериям.
Рис. 2.5. Результат поиска записи по ключевому полю
Private
Sub
Button3_Click(ByVal
sender
As
System.Object, ByVal e As System.EventArgs) Handles
Button3.Click
Dim dtEmp As DataTable = dsE.Tables("Employees")
Dim
selectedRows()
As
DataRow
selectedRows
=
dtEmp.Select("LastName='Владимир'")
Dim
i
As
Integer
For i = 0 To selectedRows.GetUpperBound(0)
MsgBox(selectedRows(i)("FirstName"))
Next
End Sub
3. Для возврата записей, отсортированных в порядке убывания, можно
отредактировать строку с методом Select так, как показано ниже. Результат
поиска с сортировкой и без нее можно увидеть на рис. 2.6.
Private Sub Button3_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button3.Click
Dim dtEmp As DataTable = dsE.Tables("Employees")
Dim
selectedRows()
As
DataRow
selectedRows
=
dtEmp.Select("LastName='Владимир'",
"FirstName
DESC")
Dim
i
As
Integer
ListBox1.Items.Add("")
ListBox1.Items.Add("========================")
ListBox1.Items.Add("Записи,
найденные
Select
с
сортировкой
по
убыванию")
For
i
=
0
To
selectedRows.GetUpperBound(0)
ListBox1.Items.Add(selectedRows(i)("FirstName"))
Next
End Sub
Рис. 2.6. Использование метода Select без сортировки и с сортировкой по убыванию
Указание состояния записи в качестве аргумента метода Select позволяет
извлекать записи с определенной версией данных непосредственно в процессе их
редактирования.
4. Например, для извлечения всех исходных записей даже после их
редактирования (но еще до вызова метода AcceptChanges) следует указать
значение OriginalRows перечисления DataViewRowState, как показано ниже.
selectedRows
=
dtEmp.Select(Nothing,
DataViewRowState.OriginalRows)
Nothing,
5. Для отбора вновь добавленных записей с именем Владимир следует указать
значение Added перечисления DataViewRowState.
selectedRows = dtEmp.Select("LastName='Владимир'",
Nothing,
DataViewRowState.Added)
6. А если требуется отобрать вновь добавленные записи с именем Владимир и
отсортировать их по фамилии, то в таком случае следует оформить строку поиска
следующим образом:
selectedRows = dtEmp.Select("LastName='Владимир'",
"FirstName
DESC",
DataViewRowState.Added)
В таблице приведены все возможные варианты состояния записи, которые
могут быть представлены членами перечисления DataViewRowState. Упомянутые в
таблице изменения связаны с последней загрузкой данных или вызовом метода
AcceptChanges.
Члены перечисления DataViewRowState
Член
Описание
Added
Вновь созданные записи
CurrentRows
Все текущие записи (включая новые, измененные или
неизмененные записи)
Deleted
Все записи, отмеченные как удаленные
ModifiedCurrent Текущая версия измененной записи
ModifiedOriginal Исходная версия измененной записи
None
Нет сведений
OriginalRows
Все исходные записи, включая
удаленные, кроме новых записей
Unchanged
Все неизмененные записи
неизмененные
и
Самостоятельно
Напишите процедуры поиска строки по значению ключевого поля и поиска
массива строк по любому поисковому критерию для проекта, реализующего
объект DataSet Dogovor.
Задание 5. Отношения между таблицами
Цель
Научиться устанавливать соответствия между полями двух таблиц, как это
принято в реляционных базах данных.
Решение
Использовать объект DataRelation, свойства ParentRelations и ChildRelations.
Обсуждение
Поскольку объект DataSet может содержать несколько таблиц, то вполне
естественно, что между ними могут существовать отношения (по крайней мере,
если речь идет о реляционных базах данных). В модели ADO.NET для этого
предусмотрен объект DataRelation.
Объект DataRelation устанавливает соответствие между полями в двух
таблицах, которые имеют родительско-дочерние отношения или связаны
первичным и внешним ключами.
Объект
DataRelation
выполняет
две
основные
функции:
Позволяет переходить от одной связанной таблицы к другой и обратно, то есть
при работе с родительской записью можно получить доступ к ее дочерним
записям, а при работе с дочерней записью - доступ к ее родительской записи.
Позволяет задавать и поддерживать ссылочную целостность, например,
каскадные обновления данных в связанных таблицах при выполнении каких-либо
изменений в любой из связанных таблиц.
1. Продолжим работу с нашим проектом. Установим
Departments и Employees родительско-дочерние отношения.
между
таблицами
Пусть в каждом отделе могут работать один или более сотрудников, но каждый
сотрудник работает в одном и только одном отделе.
2. Создайте новую кнопку CreateRelations в форме проекта и добавьте к ней
программный код, позволяющий установить указанные отношения между
таблицами.
Private
Sub
Button4_Click(ByVal
sender
As
System.Object, ByVal e As System.EventArgs) Handles
Button4.Click
Dim
rel
As
DataRelation
CreateDataSet()
'Создание отношения между таблицами Departments
и
Employees
rel
=
dsE.Relations.Add("relDepEmp",
dsE.Tables("Departments").Columns("ID"),
dsE.Tables("Employees").Columns("DepartmentID"))
DisplayRelations(dsE)
End Sub
3. Сначала нужно создать объект DataRelation.
Каждый объект DataSet содержит коллекцию отношений, которая доступна как
свойство Relations. Это свойство имеет тип DataRelationCollection и поддерживает
несколько перегруженных версий метода Add. Версия, которая была
использована нами, принимает три аргумента: имя отношения, ссылку на объект
DataColumn в родительской таблице, а также ссылку на объект DataColumn в
дочерней таблице.
Если отношение между таблицами охватывает более одного поля, то следует
использовать другую версию метода Add с аргументами-массивами объектов
DataColumn.
4. Процедура DisplayRelations циклически обходит все отношения свойства
relations объекта DataSet и выводит в ListBox имя отношения, имя родительской
таблицы и ее поле, которое входит в созданное отношение, а также имя дочерней
таблицы и ее поле, которое входит в созданное отношение.
Private Sub DisplayRelations(ByVal ds As DataSet)
Dim
rel
As
DataRelation
ListBox1.Items.Add("")
ListBox1.Items.Add("DISPLAY
RELATIONS")
For
Each
rel
In
ds.Relations
ListBox1.Items.Add("NAME: " & rel.RelationName)
ListBox1.Items.Add("PARENT:
"
&
rel.ParentTable.ToString
&
"--"
&
rel.ParentColumns(0).ColumnName)
ListBox1.Items.Add("CHILD: " & rel.ChildTable.ToString
&
"--"
&
rel.ChildColumns(0).ColumnName)
Next
ListBox1.Items.Add("")
End Sub
5. После компоновки проекта вы сможете увидеть установленные отношения
между таблицами (рис. 2.7).
Рис. 2.7. Установление отношений между таблицами
Кроме коллекции Relations объекта DataSet, которая содержит все отношения,
определенные между таблицами объекта DataSet. Каждый объект DataTable также
содержит две коллекции отношений (то есть два свойства): ParentRelations и
childRelations. Которые содержат отношения между данным объектом dataTable и
связанной с ним другой (дочерней или родительской) таблицей.
6. После создания отношения между таблицами можно организовать доступ к
связанным данным в них. Начните с создания кнопки Child Rows и вставки
программного кода, приведенного ниже.
Private
Sub
Button5_Click(ByVal
sender
As
System.Object, ByVal e As System.EventArgs) Handles
Button5.Click
Dim
rel
As
DataRelation
CreateDataSet()
AddData()
rel
=
dsE.Relations.Add("relDepEmp",
dsE.Tables("Departments").Columns("ID"),
dsE.Tables("Employees").Columns("DepartmentID"))
DisplayChildRows(dsE.Tables("Departments"))
End Sub
Процедура DisplatChildRows содержит трижды вложенный цикл для
отображения всех полей из каждой связанной таблицы (в нашем случае только
одной) для каждой записи родительской таблицы. При этом каждая запись
родительской таблицы передается циклу как аргумент, происходит обход всех
отношений, определенных в свойстве ChildRelations таблицы, отображается имя
таблицы, имя поля в родительской таблице, а также значение поля в текущей
записи. Затем вызывается метод GetChildRows с текущим отношением в качестве
аргумента и возвращается массив объектов DataRow, содержащих дочерние
записи.
7. Для каждой записи отобразите все поля с именем дочерней таблицы.
Private Sub DisplayChildRows(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
ListBox1.Items.Add("")
ListBox1.Items.Add("CHILD
ROWS")
For
Each
row
In
dt.Rows
For
Each
rel
In
dt.ChildRelations
ListBox1.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
ListBox1.Items.Add(rowData)
Next
i
Next
rel
Next
row
End Sub
8. Запуск полученного кода должен отобразить родительские и дочерние
записи из таблиц Employees и Departments (рис. 2.8).
Рис. 2.8. Результаты отображения родительских и дочерних записей
Самостоятельно
Задайте отношения для таблиц объекта DataSet Dogovor. Используя
приведенную выше процедуру отображения родительских и дочерних данных из
связанных таблиц, выполните отображение связанных данных для таблиц DataSet
Dogovor.
Задание 6. Ограничения целостности данных
Цель
Обеспечить целостность данных для уникальных
добавлении, удалении или изменении данных.
данных, а
также
при
Решение
Использовать имеющиеся в модели ADO.NET ограничения целостности данных:
UniqueConstraint и ForeignKeyConstraint.
Обсуждение
Ограничениями называются правила, которые вводятся для поддержания
целостности данных в таблице. В модели ADO.NET применяется два типа
ограничений целостности данных: UniqueConstraint и ForeignKeyConstraint.
Ограничение UniqueConstraint гарантирует, что все значения в указанных полях
будут уникальны в рамках всей таблицы. Ограничение ForeignKeyConstraint
определяет связь на основе первичного и внешнего ключа в двух таблицах и
выполняемые действия в случае добавления, удаления или изменения значений
родительской записи (то есть первичного ключа).
Хотя ограничения можно создавать непосредственно, фактически они
создаются косвенно. В нашем проекте ограничения уже созданы, так как объект
UniqueConstraint автоматически был создан и включен в коллекцию Constraints
объекта DataTable при объявлении свойства Unique объекта DataColumn равным
True. Кроме того, объекты UniqueConstraint и ForeignKeyConstraint автоматически
создаются при создании отношения между двумя таблицами. Объект
UniqueConstraint был создан для связанных полей в родительской таблице, а
объект ForeignKeyConstraint - для связанных полей в дочерней таблице.
1. Для создания и отображения ограничений таблиц используемого объекта
DataSet в нашем проекте создадим еще одну кнопку Constraints и вставим код,
приведенный ниже.
Private
Sub
Button6_Click(ByVal
sender
As System.Object, ByVal e As System.EventArgs)
Handles
Button6.Click
Dim
dt
As
DataTable,
rel
As
DataRelation
CreateDataSet()
2. Создание отношения между таблицами Departments и Employees
rel
=
dsE.Relations.Add("relDepEmp",
dsE.Tables("Departments").Columns("ID"),
dsE.Tables("Employees").Columns("DepartmentID"))
For
Each
dt
In
dsE.Tables
DisplayConstraints(dt)
Next
dt
End Sub
Процедура DisplayConstraints принимает в качестве параметра объект DataTable
и отображает информацию об ограничениях указанной таблицы. Для этого
выполняется циклический обход всех членов свойства-коллекции Constraints
указанной таблицы. Каждое найденное ограничение проверяется, то есть
выясняется имеет ли оно тип UniqueConstraint или ForeignKeyConsctaint. Оба типа
являются производными классами от класса Constraint, поэтому могут
существовать в рамках одной типизированной коллекции. Однако эти объекты все
же обладают разным набором свойств, поэтому необходимо идентифицировать
тип ограничения.
Для ограничения UniqueConstraint
определенных в данном ограничении.
отображаются
имена
всех
полей,
3. Для ограничения ForeignKeyConstraint отображается имя связанной
родительской таблицы вместе с именами всех связанных полей в этой таблице
(рис. 2.9).
Рис.2.9. Результаты отображения информации о созданных ограничениях для таблиц
Departments и Employees
Private
Sub
DisplayConstraints(ByVal
dt
As
DataTab
Dim
i
As
Inte
Dim
cs
As
Constra
Dim
uCS
As
UniqueConstra
Dim
fkCS
As
ForeignKeyConstra
Dim
columns()
As
DataColu
ListBox1.Items.Add("")
ListBox1.Items.Add("CONSTRAINTS
FOR
TABLE:
"
&
dt.TableNam
ListBox1.Items.Add("======================================")
For
Each
cs
In
dt.Constra
ListBox1.Items.Add("Constraint
Name:
"
&
cs.ConstraintNam
ListBox1.Items.Add("Type:
"
&
cs.GetType().ToStri
If
TypeOf
cs
Is
UniqueConstraint
T
uCS
=
CType(cs,
UniqueConstra
'Обработка
полей
в
виде
масс
columns
=
uCS.Colum
'Вывод
имен
по
For
i
=
0
To
columns.Length
ListBox1.Items.Add("column
Name:
"
&
columns(i).ColumnNam
Next
ElseIf
TypeOf
cs
Is
ForeignKeyConstraint
Th
fkCS
=
CType(cs,
ForeignKeyConstra
'Обработка
дочерних
полей
и
вывод
их
им
columns
=
fkCS.Colum
For
i
=
0
To
columns.Length
ListBox1.Items.Add("Column
Name:
"
&
columns(i).ColumnNam
Next
Вывод
имени
связанной
родительской
табли
ListBox1.Items.Add("Related Table Name: " & fkCS.RelatedTable.TableNam
'Обработка
связанных
родительских
полей
и
вывод
их
им
columns
=
fkCS.RelatedColum
For
i
=
0
To
columns.Length
ListBox1.Items.Add("Related
Column
Name:
"
&
columns(i).ColumnNam
Next
End
ListBox1.Items.Add("=======================================
Next
End Sub
4. После запуска проекта вы должны увидеть информацию об ограничениях,
созданных автоматически (рис. 2.8).
Объект ForeignKeyConstraint имеет три свойства-правила: UpdateRule,
DeleteRule, AcceptRejectRule. Эти свойства-правила управляют действиями,
выполняемыми над записями при редактировании данных в связанных таблицах.
Свойства UpdateRule и DeleteRule принимают одно из значений перечисления
Rule, описанного ниже в таблице.
Члены перечисления Rule
Член
Описание
Cascade
Удаление или обновление данных в родительской записи
также выполняется для связанных дочерних записей. Это
значение по умолчанию
None
Удаление или обновление данных в родительской записи не
выполняется для связанных дочерних записей. Это может
привести к появлению дочерних записей, которые ошибочно
ссылаются на отсутствующие родительские записи
Удаление или обновление данных в родительской записи не
выполняется для связанных дочерних записей, но для них
SetDefault
задается используемое по умолчанию значение, указанное в
свойстве DefaultValue
SetNull
Удаление или обновление данных в родительской записи не
выполняется для связанных дочерних записей, но для них
задается значение DBNull
Еще одно свойство AcceptRejectRule может принимать значения Cascade (по
умолчанию) или None при вызове метода AcceptChanges (или RejectChanges) для
связанных дочерних записей. Это свойство указывает на автоматический вызов
(Cascade) методов AcceptChanges или RejectChanges для дочерних записей при
вызове этих методов для родительской записи. В случае None вызов методов для
родительской записи никак не повлияет на связанные с ней дочерние записи.
Самостоятельно
Примените процедуру просмотра имеющихся ограничений для таблиц объекта
DataSet Dogovor. Убедитесь, что все уникальные поля таблиц и установленные
вами связи между таблицами реализованы в объектах UniqueConstraint и
ForeignKeyConstraint.
Задание 7. Визуальное программирование объекта
DataSet
Цель
Создать объект DataSet средствами визуального программирования
Решение
Использовать панель инструментов Data среды Visual Studio.NET.
Обсуждение
Панель элементов управления Data среды Visual Studio,NET содержит
компонент DataSet, который позволяет задавать значения свойств для набора
данных с помощью окна свойств Properties вместо создания специального кода.
Воспользуемся этим способом для создания объекта DataSet, аналогичного тому,
который программировался в предыдущих заданиях (таблицы Empoyees и
Departments).
Выполните
перечисленные
далее
действия:
1. Добавьте в проект еще одну Windows-форму. Свойству Text формы присвойте
значение
DataSet_Properties.
2.
Разместите
на
форме
элемент
управления
ListBox.
3. Из панели элементов управления Data перетащите в форму компонент DataSet.
В открывшемся диалоговом окне выберите переключатель Untyped Dataset
(Нетипизированный набор данных), нажмите Ок.
Этот компонент невидим во время выполнения приложения, поэтому в режиме
создания
приложения
он
будет
находиться
под
формой.
1. В окне свойств Properties этого компонента укажите значение dsE для свойства
Name.
2. В окне свойств Properties этого компонента выберите свойство Tables и
щелкните на кнопке с многоточием для отображения диалога Tables Collection
Editor
(Редактор
коллекции
таблиц).
3. Щелкните на кнопке Add для отображения свойств первой таблицы
создаваемого
набора.
4. В панели свойств Table1 Properties укажите значение Employees для свойства
TableName
(рис.
2.10).
5. В панели свойств Empoyees Properties выберите свойство Columns и щелкните
на кнопке с многоточием для отображения диалога Columns Collection Editor
(Редактор коллекций полей).
Рис. 2.10. Диалоговое окно Tables Collection Editor после указания таблицы Employees
6. Щелкните на кнопке Add для отображения свойств первого поля таблицы
Employees.
7. В панели свойств Column1 Properties укажите значение FirstName для свойства
ColumnName
первого
поля.
8. Щелкните на кнопке Add для отображения свойств второго поля таблицы
Empoyees.
9. В панели свойств Column1 Properties укажите значение LastName для свойства
ColumnName
второго
поля.
10. Щелкните на кнопке Add для отображения свойств третьего поля таблицы
Employees.
11. В панели свойств column1 Properties укажите значение DepartmentID для
свойства СolumnName и значение System.Int32 для свойства DataType третьего
поля.
После выполнения этих действий диалог Column Collection Editor будет
выглядеть так, как показано на рис. 2.11.
Рис. 2.11. Диалоговое окно Columns Collection Editor со свойствами полей таблицы
Employees
12. Щелкните на кнопке Close в диалоге Column Collection Editor. Чтобы
вернуться в диалоговое окно Tables collection Editor для включения в набор
данных
dsE
еще
одной
таблицы
Departments.
13. Щелкните на кнопке Add для отображения свойств второй таблицы набора
данных
dsE.
14. В панели свойств Table1 Properties укажите значение Departments для
свойства
TableName
второй
таблицы.
15. Укажите значение 5 для свойства MinimumCapacity второй таблицы.
16. В панели свойств Departments properties укажите свойство columns и
щелкните на кнопке с многоточием для отображения диалога Columns Collection
Editor.
17. Щелкните на кнопке Add для отображения свойств первого поля таблицы
departments.
18. Укажите значение ID для свойства ColumnName и значение System.Int32 для
свойства
DataType
первого
поля.
19. В панели свойств ID Properties укажите значение True для свойства ReadOnly,
значение True для свойства Unique и значение true для свойства AutoIncrement
первого
поля.
20. Щелкните на кнопке Add для отображения свойств второго поля таблицы
Departments.
21. В панели свойств Column1 properties укажите значение DepartmentName для
свойства
ColumnName.
22. В панели свойств DepartmentName properties укажите значение true для
свойства Unique и значение False для свойства AllowDBNull первого поля.
23. Щелкните на кнопке Close в диалоговом окне Columns Collection Editor для
возвращения
в
диалоговое
окно
Tables
Collection
Editor.
24. Итак, вы создали набор данных dsE с таблицами Employees и Departments,
указывая для свойств те же значения, которые использовались в коде.
Продолжим работу с этими компонентами и определим отношения между
таблицами
набора
данных
dsE.
25. В окне свойств Properties компонента dsE выберите свойство Relations, а затем
щелкните на кнопке с изображением многоточия, чтобы отобразить диалог
Relations
Collection
Editor
(Редактор
коллекции
отношений).
26. Щелкните на кнопке Add для вызова диалога Relation набора dsE.
27. В текстовом окне Name укажите значение relDepartmentEmployees.
28.
В
текстовом
окне
ParentTable
выберите
таблицу
Departments.
29.
В
текстовом
окне
ChildTable
выберите
таблицу
Employees.
30. В поле со списком столбца Key Columns раздела columns выберите поле ID, в
результате этого значение ID будет присвоено свойству ParentColumns объекта
relDepartmentEmployees.
31. Аналогично в поле со списком столбца Foreign Key Columns раздела Columns
выберите поле DepartmentID, в результате этого значение DepartmentID будет
присвоено свойству ChildColumns объекта relDepartmentEmployees.
Воспользуйтесь предлагаемыми по умолчанию значениями в списках
UpdateRule
(Правило
обновления,)
DeleteRule
(Правило
удаления)
и
Accept/RejectRule (Правило подтверждения/отказа), которые соответствуют
свойствам
UpdateRule,
DeleteRule
и
Accept/RejectRule.
32. Щелкните на кнопке ОК для закрытия диалога Relation, а затем на кнопке
Close диалога Relations Collection Editor.
Теперь остается указать значения свойства PrimaryKey для каждой таблицы.
33. В окне свойств Properties компонента dsE выберите свойство Tables, а затем
щелкните на кнопке с изображением многоточия, чтобы отобразить диалог Tables
Collection
Editor.
34. В списке членов набора данных Members выберите свойство PrimaryKey и
щелкните на кнопке с изображением стрелки в правой части этого свойства для
развертывания
списка
полей.
35. Установите флажки для поля (или нескольких полей) первичного ключа из
списка доступных полей. Если первичный ключ охватывает несколько полей, то
выберите их в правильном порядке. В нашем случае выберите сначала поле
FirsName,а затем LastName, как показано на рис. 2.12.
Рис. 2.12. Выбор нескольких полей для определения первичного ключа
36. Нажмите клавишу ENTER для утверждения созданного первичного ключа.
37. В списке членов набора данных Members выберите таблицу Departments.
38. В панели свойств Departments Properties выберите свойство PrimaryKey и
щелкните на кнопке со стрелкой для развертывания списка полей.
39. Установите флажок для поля ID первичного ключа из списка доступных полей.
40. Щелкните на кнопке Close для закрытия текущего диалога.
Чтобы убедиться в идентичности результатов, полученных в режиме создания
компонентов, по сравнению с созданным ранее кодом скопируйте и вставьте
некоторые процедуры из формы DataSet в форму DataSet_Properties, а затем
запустите полученное приложение, выполнив перечисленные ниже действия.
1. Выберите и скопируйте процедуру AddData из формы DataSet в форму
DataSet_Properties.
2.
Повторите
п.1
для
процедуры
DisplayDataSet
и
DisplayChildRows.
3. Включите следующий программный код в код обработчика события загрузки
формы DataSet_Properties_Load в форме DataSet_Properties:
Private Sub Form5_Load(ByVal sender As Object, ByVal
e
As
System.EventArgs)
Handles
MyBase.Load
AddData()
DisplayDataset()
DisplayChildRows(dsE.Tables("Departments"))
End
Sub
Private
Sub
AddData()
End
Sub
Private
Sub
DisplayDataset()
End
Sub
Private Sub DisplayChildRows(ByVal dt As DataTable)
End Sub
После запуска созданного приложения в поле со списком формы
DataSet_Properties будут отображены все данные набора dsE и дочерние записи
из
таблицы
Departments
(рис.
2.13).
Анализируя код, сгенерированный при редактировании свойств в режиме
создания компонентов, можно убедиться в том, что он очень похож на созданный
вручную код, описанный в предыдущих заданиях. Для просмотра автоматически
созданного кода нужно выбрать форму в окне Solution Explorer, щелкнуть правой
кнопкой мыши, выбрать команду меню View Code в контекстном меню, а затем
раскрыть раздел Windows Form Designer generation code.
Рис. 2.13. Отображение всех данных набора Department_Employees и дочерних записей
с помощью параметров объекта DataSet, заданных в режиме создания компонентов
(визуального программирования).
Самостоятельно
Создайте объект DataSet в режиме создания компонентов (панель Data) для
модели Dogovor. Проверьте идентичность результатов создания таблиц,
установления связей, заполнения таблиц для случая программного кодирования
объекта DataSet и для случая визуального программирования. Воспользуйтесь
разработанными процедурами отображения дочерних записей связанных таблиц.
Download