FULL ACCESS Пятница, 22.11.2024, 13:43
Приветствую Вас Гость | RSS
Меню сайта

Категории раздела
Структура [3]
Статьи о работе со структурой данных как на низком уровне, так и на уровне схемы данных
Интерфейс [2]
Статьи описывающие приёмы работы с интерфейсом
Разное [1]
Разные статьи на темы о базах данных
Автоматизация [1]
Статьи про автоматизированные системы, автоматизацию проектирования.

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Сертификаты. Рейтинги

Партнёры

Главная » Статьи » Структура

Создание базы данных с помощью ADO

Команда меню «Файл/Создать…»

Чтобы пользователю было легче изучить то, с чем ему придётся работать, интерфейс должен обладать одним замечательным свойством: «дружелюбностью». Причём это обязательное условие, ведь пользователю зачастую навязывается новое приложение, когда он (пользователь) и без него не плохо справляется – привык. Для Windows приложений «дружелюбность интерфейса» означает, чтобы были панели меню и инструментов, как в любой другой программе.
Привычными и неотъемлемыми элементами интерфейса Windows приложений являются меню «Файл» и команды «Создать», «Открыть».
Команда «Создать» создаёт новый файл – экземпляр документа, таблицы, базы данных и др.
Команда «Открыть» открывает сохранённый файл (документ, таблицу, базу данных).
Рассмотрим вопросы реализации этих команд в приложениях MS Access.

Разделяй и властвуй

Реализация команд «Создать» и «Открыть» в приложениях MS Access актуальна для разделённых баз данных (формат файлов mdb). Когда интерфейс приложения отделён от данных, тогда есть возможность и смысл применять данные команды.
Команда «Открыть» не рассматривается в данной статье. Она выполняет присоединение таблиц открываемой базы данных к интерфейсной части приложения.

Команда «Создать»

Данная команда создаёт пустую базу данных той же структуры, для которой написан или разрабатывается интерфейс (если расширять применение данной команды) и присоединяет её таблицы к интерфейсной части приложения. Рассмотрим только создание пустой базы данных с определённой структурой таблиц.
Для создания базы данных нужно программно выполнить следующий алгоритм:
- создать новый файл базы данных;
- создать в новой базе таблицы;
- создать в каждой таблице столбцы;
- установить все свойства каждого столбца в соответствии со структурой базы данных;
- создать в каждой таблице индексы;
- создать связи между таблицами.

Сохранение информации о структуре

Логичнее будет не писать для каждой структуры базы данных свои функции по созданию таблиц в соответствии с данным алгоритмом, а использовать общие функции. Тогда общие функции должны откуда-то брать информацию о структуре базы данных: таблицах, столбцах и их свойствах, индексах, связях.
Можно хранить эту информацию в таблицах интерфейсной части приложения. Заполнять таблицы информацией о структуре базы данных программно по следующему алгоритму:
- для каждой таблицы базы данных:
- записать в таблицу имена столбцов;
- для каждого столбца при этом записать в таблицу значения всех его (столбца) свойств;
- записать в таблицу информацию об индексах;
- для каждого индекса записать в таблицу информацию о столбцах;
- записать в таблицу информацию о связях;
- для каждой связи записать информацию о столбцах.

Схема данных для этих таблиц представлена на следующем рисунке:

Size
Название столбцаТип данныхОписание
Таблица Structure - структура
IDСчётчикКлючевое поле
TableТекстовыйНазвание таблицы
Таблица ColumnsT - столбцы таблиц
IDСчётчикКлючевое поле
TableЧисловойКод таблицы из Structure
NameТекстовыйНазвание столбца
TypeЧисловойТип столбца
ЧисловойРазмер столбца
KeyЛогическийTrue, если столбец является ключевым
Таблица PropertiesT - свойства столбцов таблиц
IDСчётчикКлючевое поле
ColumnTЧисловойКод столбца из ColumnsT
NameТекстовыйНазвание свойства
TypeЧисловойТип свойства
ValueТекстовыйЗначение свойства столбца
Таблица Indexes - индексы таблиц
IDСчётчикКлючевое поле
TableЧисловойКод таблицы из Structure
NameТекстовыйНазвание индекса
PrimaryKeyЛогическийTrue, если индекс - PrimaryKey
UniqueЛогическийTrue, если индекс уникальный
Таблица ColumnsI - столбцы индекса
IDСчётчикКлючевое поле
IndexЧисловойКод индекса из Indexes
NameТекстовыйНазвание столбца, входящего в индекс
Таблица Keys - ключи (связи)
IDСчётчикКлючевое поле
TableЧисловойКод таблицы из Structure
NameТекстовыйНазвание ключа (связи)
TypeЧисловойТип связи
RelatedTableТекстовыйНазвание связанной таблицы
UpdateRuleЧисловойПравило обновления
DeleteRuleЧисловойПравило удаления
Таблица ColumnsK - столбцы связи
IDСчётчикКлючевое поле
KeyЧисловойКод ключа (связи) из Keys
NameТекстовыйНазвание столбца связи
RelatedColumnТекстовыйНазвание связанного столбца

В Листинге 1 представлен код извлечения информации о структуре базы данных и заполнения соответствующих таблиц.

Листинг 1

Public Sub faGetStructure(strDB as String)
'запомнить информацию о структуре базы данных в специальных таблицах
'strDB - это полный путь к базе данных, у которой сохраняем информацию о структуре
Dim cat As ADOX.Catalog
Dim tbl As ADOX.Table
Dim idx As ADOX.Index
Dim ky As ADOX.Key
Dim clm As ADOX.Column
Dim prp As ADOX.Property
Dim rstTables As ADODB.Recordset
Dim rst As ADODB.Recordset
Dim rstPrp As ADODB.Recordset
Dim lngID As Long
If strDB = vbNullString Then Exit Sub 'если не выбрали файл, то выходим
Set cat = New ADOX.Catalog
cat.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & strDB & ";"
Set rstPrp = New ADODB.Recordset
rstPrp.Open "PropertiesT", CurrentProject.Connection, adOpenKeyset, adLockOptimistic, adCmdTableDirect
Set rstTables = New ADODB.Recordset
With rstTables
.Open "Structure", CurrentProject.Connection, adOpenKeyset, adLockOptimistic, adCmdTableDirect
'если списка таблиц нет, то его надо создать
If .RecordCount = 0 Then
'вызываем функцию для создания списка таблиц сохраняемой базы данных
faGetTableList cat, rstTables
End If
Set rst = New ADODB.Recordset
Do Until .EOF 'цикл по всем таблицам в списке
rst.Open "ColumnsT", CurrentProject.Connection, adOpenDynamic, adLockOptimistic, adCmdTableDirect
For Each tbl In cat.Tables'заполнение столбцов таблиц
If tbl.Name = .Fields("Table") Then
For Each clm In tbl.Columns
rst.AddNew
rst.Fields("Table") = .Fields("ID")
rst.Fields("Name") = clm.Name
rst.Fields("Type") = clm.Type
rst.Fields("Size") = clm.DefinedSize
rst.Fields("Attributes") = clm.Attributes
rst.Fields("Key") = clm.Properties("AutoIncrement")
rst.Update
For Each prp In clm.Properties
rstPrp.AddNew
rstPrp.Fields("ColumnT") = rst.Fields("ID")
rstPrp.Fields("Name") = prp.Name
rstPrp.Fields("Type") = prp.Type
rstPrp.Fields("Value") = prp.Value
rstPrp.Update
Next
Next
Set rst = Nothing
Set rst = New ADODB.Recordset
'rst.Close
For Each idx In tbl.Indexes
rst.Open "Indexes", CurrentProject.Connection, adOpenDynamic, adLockOptimistic, adCmdTableDirect
If idx.Name = "PrimaryKey" Then
rst.AddNew
rst.Fields("Table") = .Fields("ID")
rst.Fields("Name") = idx.Name
rst.Fields("PrimaryKey") = idx.PrimaryKey
rst.Fields("Unique") = idx.Unique
rst.Update
lngID = rst.Fields("ID")
rst.Close
rst.Open "ColumnsI", CurrentProject.Connection, adOpenDynamic, adLockOptimistic, adCmdTableDirect
For Each clm In idx.Columns
rst.AddNew
rst.Fields("Index") = lngID
rst.Fields("Name") = clm.Name
rst.Update
Next
End If
rst.Close
Next
For Each ky In tbl.Keys
rst.Open "Keys", CurrentProject.Connection, adOpenDynamic, adLockOptimistic, adCmdTableDirect
If ky.Name <> "PrimaryKey" Then
rst.AddNew
rst.Fields("Table") = .Fields("ID")
rst.Fields("Name") = ky.Name
rst.Fields("Type") = ky.Type
rst.Fields("RelatedTable") = ky.RelatedTable
rst.Fields("UpdateRule") = ky.UpdateRule
rst.Fields("DeleteRule") = ky.DeleteRule
rst.Update
lngID = rst.Fields("ID")
rst.Close
rst.Open "ColumnsK", CurrentProject.Connection, adOpenDynamic, adLockOptimistic, adCmdTableDirect
For Each clm In ky.Columns
rst.AddNew
rst.Fields("Key") = lngID
rst.Fields("Name") = clm.Name
rst.Fields("RelatedColumn") = clm.RelatedColumn
rst.Update
Next
End If
rst.Close
Next
End If
Next
.MoveNext
Loop
End With
End Sub
Public Sub faGetTableList(cat As ADOX.Catalog, rst As ADODB.Recordset)
'сохранение списка таблиц открытой базы (каталог ADOX) в наборе записей rst
On Error GoTo ErrHolder
Dim tbl As ADOX.Table
With rst 
For Each tbl In cat.Tables
If tbl.Type = "TABLE" Then
.AddNew
.Fields("Table") = tbl.Name
.Update
End If
Next
.MoveFirst
End With
ExitHere:
Exit Sub
ErrHolder:
MsgBox Err.Number & ": " & Err.Description, vbExclamation, "Error"
Resume ExitHere
End Sub
Итак, для сохранения информации о структуре базы данных в таблицах, рассмотренных выше, необходимо запустить процедуру faGetStructure при этом, передав ей в качестве параметра полное имя файла базы данных, структуру которой необходимо сохранить.
Данная процедура использует вспомогательную процедуру faGetTableList в случае, если таблица Structure окажется пустой. Вспомогательная процедура заполнит данную таблицу названиями всех таблиц из сохраняемой базы данных. Можно использовать данную особенность для того, чтобы сохранить информацию не о всей структуре базы данных, а только о части, представленной определёнными таблицами, для этого нужно вручную заполнить таблицу Structure названиями таблиц сохраняемой структуры.
Процедура faGetStructure для каждого наименования таблицы из Structure сохранит в таблицах информацию о столбцах и их свойствах таблиц, индексов, ключей.
Таким образом, мы сохранили информацию о структуре базы данных и можем использовать эту информацию многократно. Если структура базы данных поменяется, то достаточно удалить всю информацию из таблицы Structure и заново вызвать процедуру faGetStructure.

Коррекция сохранённой структуры

Сохранённая информация о структуре требует коррекции, иначе могут возникнуть ошибки при создании новой базы данных. Коррекция заключается в удалении из таблицы PropertiesT свойств столбцов таблицы всех полей, относящихся к свойствам с именами “Seed” (насколько могу судить: значение идентификатора для первой строки таблицы) и “Increment” (приращение для столбца идентификатора), т.к. эти свойства невозможно установить программно, как выяснилось эмпирически. На счёт свойства “Increment” могу предположить, что его нельзя задать, т.к. MS Access (Jet) признаёт любые значения “Increment”, при условии, что они равны 1 (единице). Из-за того, что необходимость коррекции выяснилась эмпирическим способом, она не отражена в коде, представленном в Листинге 1. Для проведения этой коррекции можно использовать такой запрос:
DELETE PropertiesT.Name
FROM PropertiesT
WHERE (((PropertiesT.Name)="Seed" Or (PropertiesT.Name)="Increment"));

Также требуется подкорректировать значения свойства “Nullable” у столбцов с логическим типом данных: оно должно быть всегда равно нулю. Этой корректировки также нет в Листинге 1, для этой цели можно использовать такой запрос:
UPDATE ColumnsT INNER JOIN PropertiesT ON ColumnsT.ID = PropertiesT.ColumnT SET PropertiesT.[Value] = "0"
WHERE (((ColumnsT.Type)=11) AND ((PropertiesT.Name)="Nullable"));

Также эмпирическим путём выяснилось, что для свойства “Fixed Length” («фиксированная длина») ключевых полей с числовым типом данных не может быть значение “False” («ложь»), хотя по неизвестным причинам при сохранении такое значение этого свойства записывается. Поэтому для данного случая также требуется коррекция. В виде запроса эта коррекция выглядит следующим образом:
UPDATE ColumnsT INNER JOIN PropertiesT ON ColumnsT.ID = PropertiesT.ColumnT SET PropertiesT.[Value] = "-1"
WHERE (((PropertiesT.Value)="0") AND ((ColumnsT.Type)=3) AND ((ColumnsT.Key)=True) AND ((PropertiesT.Name)="Fixed Length"));

Само собой разумеется, что значение свойства “JET OLEDB:Allow Zerro Length” («допускается нулевая длина») для ключевых полей с числовым типом данных не может быть “True” («истина»), но и такое бывает, поэтому и для этого варианта предусматриваем коррекцию в виде запроса:
UPDATE ColumnsT INNER JOIN PropertiesT ON ColumnsT.ID = PropertiesT.ColumnT SET PropertiesT.[Value] = "0"
WHERE (((PropertiesT.Value)="-1") AND ((ColumnsT.Type)=3) AND ((ColumnsT.Key)=True) AND ((PropertiesT.Name)="Jet OLEDB:Allow Zero Length"));

Эту коррекцию можно легко внедрить в код сохранения информации о структуре базы данных в виде вызова отдельных процедур.
Ещё одно замечание. Если в сохраняемой структуре базы данных были пользовательские таблицы с именами, начинающимися на “MSys”, как у системных таблиц Access, то при сохранении таблицы программно возникнет ошибка. Поэтому перед созданием базы данных по сохранённой структуре, нужно изменить название таких таблиц в таблице Structure. А после создания базы данных переименовать эти таблицы обратно.

Создание новой базы данных по сохранённой структуре

Теперь можно создавать неограниченное число раз чистых копий баз данных, аналогичных по структуре исходной, информация о которой была сохранена и скорректирована.
В Листинге 2 представлен код для создания базы данных по уже сохранённой структуре.

Листинг 2

Public Function faCreateStructure(strDB As String) As Boolean
'создание файла базы данных с сохранённой структурой
On Error GoTo ErrHolder

Dim cat As ADOX.Catalog
Dim tbl As ADOX.Table
Dim idx As ADOX.Index
Dim ky As ADOX.Key
Dim clm As ADOX.Column
Dim prp As ADOX.Property
Dim rst As ADODB.Recordset
Dim rstClm As ADODB.Recordset
Dim rstTables As ADODB.Recordset
Dim rstPrp As ADODB.Recordset

If strDB <> vbNullString Then

Set cat = New ADOX.Catalog
cat.Create "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & strDB & ";"

Set rstTables = New ADODB.Recordset
Set rstClm = New ADODB.Recordset
Set rst = New ADODB.Recordset
Set rstPrp = New ADODB.Recordset

With rstTables
.Open "Structure", CurrentProject.Connection, , , adCmdTableDirect
Do Until .EOF
Set tbl = New ADOX.Table
rstClm.Open _
"SELECT * FROM ColumnsT WHERE ColumnsT.Table=" & .Fields("ID"), _
CurrentProject.Connection, , , adCmdText
tbl.Name = .Fields("Table")
Do Until rstClm.EOF
'добавление столбцов
Set clm = New ADOX.Column
clm.Name = rstClm.Fields("Name")
clm.Type = rstClm.Fields("Type")
If rstClm.Fields("Size") > 0 Then
clm.DefinedSize = rstClm.Fields("Size")
End If
tbl.Columns.Append clm
rstClm.MoveNext
Loop
'заполнение свойств столбцов
rstClm.MoveFirst
Do Until rstClm.EOF
Set clm = tbl.Columns("" & rstClm.Fields("Name") & "")
Call faSetPropertiesC(cat, clm, rstClm.Fields("ID"))
rstClm.MoveNext
Loop
rstClm.Close
'присоединение таблицы
cat.Tables.Append tbl
.MoveNext
Loop
'добавление индексов к таблицам
.MoveFirst
Do Until .EOF
Set tbl = cat.Tables("" & .Fields("Table") & "")
rst.Open _
"SELECT * FROM Indexes WHERE Indexes.Table=" & .Fields("ID"), _
CurrentProject.Connection, , , adCmdText
Do Until rst.EOF
Set idx = New ADOX.Index
idx.Name = rst.Fields("Name")
idx.PrimaryKey = rst.Fields("PrimaryKey")
idx.Unique = rst.Fields("Unique")
'присоединение столбцов
rstClm.Open _
"SELECT * FROM ColumnsI WHERE ColumnsI.Index=" & rst.Fields("ID"), _
CurrentProject.Connection, , , adCmdText
Do Until rstClm.EOF
idx.Columns.Append "" & rstClm.Fields("Name") & ""
rstClm.MoveNext
Loop
tbl.Indexes.Append idx
rst.MoveNext
rstClm.Close
Loop
rst.Close
.MoveNext
Loop
'добавление ключей (связей) таблиц
.MoveFirst
Do Until .EOF
Set tbl = cat.Tables("" & .Fields("Table") & "")
rst.Open _
"SELECT * FROM Keys WHERE Keys.Table=" & .Fields("ID"), _
CurrentProject.Connection, , , adCmdText
Do Until rst.EOF
Set ky = New ADOX.Key
ky.Name = rst.Fields("Name")
ky.Type = rst.Fields("Type")
ky.RelatedTable = rst.Fields("RelatedTable")
'присоединение столбцов
rstClm.Open _
"SELECT * FROM ColumnsK WHERE ColumnsK.Key=" & rst.Fields("ID"), _
CurrentProject.Connection, , , adCmdText
Do Until rstClm.EOF
ky.Columns.Append "" & rstClm.Fields("Name") & ""
If Not IsNull(rstClm.Fields("RelatedColumn")) Then
ky.Columns("" & rstClm.Fields("Name") & "").RelatedColumn = rstClm.Fields("RelatedColumn")
End If
rstClm.MoveNext
Loop
ky.UpdateRule = rst.Fields("UpdateRule")
ky.DeleteRule = rst.Fields("DeleteRule")
tbl.Keys.Append ky
rst.MoveNext
rstClm.Close
Loop
.MoveNext
rst.Close
Loop
End With

faCreateStructure = True

End If

ExitHere:
Set tbl = Nothing
Set idx = Nothing
Set ky = Nothing
cat.ActiveConnection.Close
Set cat = Nothing
Exit Function
ErrHolder:
Select Case Err.Number
Case -2147217868 'индекс уже существует
Resume Next
Case Else
faCreateStructure = False
MsgBox Err.Number & ": " & Err.Description, vbExclamation
Resume ExitHere
End Select
End Function

Public Function faSetPropertiesC(ByRef cat As ADOX.Catalog, _
ByRef clm As ADOX.Column, ID As Long) As Boolean
'заполнение свойств столбцов таблицы
On Error GoTo ErrHolder

Dim prp As ADOX.Property
Dim rstClm As ADODB.Recordset
Dim rstTables As ADODB.Recordset
Dim rstPrp As ADODB.Recordset

Set rstTables = New ADODB.Recordset
Set rstClm = New ADODB.Recordset
Set rstPrp = New ADODB.Recordset

clm.ParentCatalog = cat
rstPrp.Open _
"SELECT * FROM PropertiesT WHERE PropertiesT.ColumnT=" & ID, _
CurrentProject.Connection, , , adCmdText
Do Until rstPrp.EOF
Select Case rstPrp.Fields("Type")
Case adBoolean
If CBool(rstPrp.Fields("Value")) Then
clm.Properties("" & rstPrp.Fields("Name") & "") = True
Else
clm.Properties("" & rstPrp.Fields("Name") & "") = False
End If
Case adInteger
clm.Properties("" & rstPrp.Fields("Name") & "") = _
CLng(rstPrp.Fields("Value"))
Case adVariant
clm.Properties("" & rstPrp.Fields("Name") & "") = _
CVar(rstPrp.Fields("Value"))
Case Else
clm.Properties("" & rstPrp.Fields("Name") & "") = _
rstPrp.Fields("Value")
End Select
rstPrp.MoveNext
Loop
Debug.Print clm.Name
For Each prp In clm.Properties
Debug.Print prp.Name & ": "; prp.Value
Next
rstPrp.Close
faSetPropertiesC = True
ExitHere:
Set prp = Nothing
Exit Function
ErrHolder:
Select Case Err.Number
Case -2147217868 'индекс уже существует
Resume Next
Case Else
faSetPropertiesC = False
MsgBox Err.Number & ": " & Err.Description, vbExclamation
Resume ExitHere
End Select
End Function

Для создания новой пустой базы данных сохранённой структуры нужно вызвать процедуру faCreateStructure и передать ей в качестве параметра полное имя файла создаваемой базы данных.
Сначала эта процедура создаёт новую базу данных как каталог ADOX, затем, используя информацию из таблиц, создаёт каждую таблицу, столбцы и заполняет их свойства. Для заполнения свойств столбцов используется вспомогательная процедура faSetPropertiesC. Данная процедура заполняет свойства, согласуясь с типом самого свойства.
Далее процедура создаёт и заполняет свойства индексов и ключей таблиц базы данных.
В результате получаем копию сохранённой базы данных, но без данных.



Источник: http://авторская статья
Категория: Структура | Добавил: DenisV (02.07.2009) | Автор: Denis V.
Просмотров: 2922 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Поиск

Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz

  • content by Denis V. 2024 Бесплатный хостинг uCoz