Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Документный метод доступа к иерархической базе данных.
АННОТАЦИЯ
В предлагаемом методе возможные типы хранимых объектов определяются схемой иерархической базы данных. Для каждого типа объекта генерируется пара классов С++. Сгенерированный код собирается в библиотеку, при помощи которой хранимые типы документов могут гладко отображаться в объекты С++ и Visual Basic. Базовая функциональность сгенерированных классов может быть расширена, с учетом возможных изменений схемы базы данных в процессе разработки, прозрачно для прикладной программы.
1 Назначение
В настоящем документе описана реализация метода доступа к иерархической БД, в которой хранятся документы. В центре метода стоит схема иерархической базы данных. В схеме концептуально выделяются один или несколько типов документов. В предельном случае любой массив структур в схеме базы данных может считаться массивом документов.
Далее мы используем общепринятые термины «документ» и «объект», как взаимозаменяемые. Документ понимается как составной информационный объект произвольной сложности. Структура документа предполагается иерархической. Документ может включать вложенные объекты: части документа и поддокументы. Например, в одной базе данных тип документа «Договор» может включать несколько частей типа «Раздел», а в другой базе данных тип документа «Институт» может включать тип поддокумента «Отдел». Поддокумент может рассматриваться как самостоятельный полноправный документ.
Каждый экземпляр документа может состоять из множества свойств и подобъектов. Предлагаемый метод доступа обрабатывает документ как единый объект. При загрузке документа из БД в память, все вложенные структуры загружаются до массивов. Элементы массивов могут затем загружаться из БД в память по требованию прикладной программы. При сохранении измененного документа в БД, вместе с ним в БД сохраняются все измененные вложенные объекты и их свойства.
Для языка С++ в нашем методе доступа генерируется код, включающий классы для документа и его частей. Из сгенерированных классов создается динамическая библиотека, сквозь которую проходят все обращения к документу. В то время как базовые свойства документа поддерживаются системой, базовая функциональность может быть расширена пользователем. Таким способом можно например, добавлять в документ «синтетические», вычислимые свойства, прозрачно для конечного приложения.
Документный метод доступа гладко стыкуется с языками С++ и Visual Basic (VB). Документы и части документов отображаются на такие «штатные» средства работы с информационными объектами, как классы C++ и COM-объекты в VB.
Приоритетными целями при разработки документного метода доступа были следующие:
· Гладкость встраивания хранимого документа в программу на С++ и VB.
· Экономность прикладного программирования.
· Интуитивность API.
· Возможность расширения базовой функциональности прозрачно для прикладной программы.
2 Источники
В качестве иерархической СУБД мы используем СУБД Ника [1].
Схема одноразовой генерации кода С++ для пользовательских классов «СMyClass», в сочетании с повторной генерацией кода С++ для базовых классов «x_СMyClass», была применена Bob Foster и др. в архитектуре визуального проектирования графического интерфейса пользователя на платформе Macintosh [2].
В статье Д. Порая и А. Голоусиковой [3] описан подход к хранению COM-объектов над иерархической базой данных, в котором схема базы данных заменяется библиотекой типов COM-объектов. Этот интересный подход диаметрально противоположен нашему, в котором напротив, возможные типы хранимых объектов определяются схемой базы данных.
3 Отличительные особенности
Метод документного доступа обладает следующими отличительными особенностями:
· В центре метода стоит схема иерархической базы данных. В схеме концептуально выделяются один или несколько типов документов. В предельном случае любой массив структур в схеме базы данных может считаться массивом документов.
· Структурные типы объектов загружаются из БД в память сразу полностью. Новые элементы структур могут быть созданы в памяти по требованию, прозрачно для прикладной программы.
· Для каждого экземпляра массива поддерживается кэширование. Элементы массива могут кэшироваться либо по требованию, либо, для небольших массивов, весь массив может загружаться в память.
· Все загруженные вершины БД включаются в общее дерево на памяти. Каждая вершина БД одновременно может быть загружена не более чем в одном экземпляре.
· Для сборки мусора используется сочетание счетчиков использования с механизмом прямой утилизации.
· Генерация кода С++ позволяет расширять базовую функциональность прозрачно для прикладной программы.
· Базовая функциональность сгенерированных классов может быть расширена, с учетом возможных изменений схемы базы данных в процессе разработки, прозрачно для прикладной программы. При изменении схемы базы данных, следует перегенерировать код утилитой «dod2cpp», см. ниже п.4.3. При этом перегенерируются только базовые классы «x_СMyClass». Пользовательские классы «СMyClass» сохранятся с теми расширениями, которые могли быть внесены в сгенерированный код.
4 Пример использования
Приводимые примеры прикладного программного кода должны проиллюстрировать, насколько достигаются эти цели в данной реализации документного метода доступа.
4.1 Пример схемы БД
Для примеров мы будем далее использовать следующую схему БД. В левой колонке показан номер вершины в ДОД. В БД Ника считается, что корень БД имеет номер 17, поэтому номера в левой колонке в следующей схеме БД начинаются с 18:
Таблица 1. Пример схемы БД в файле «Sample. txt».
// Список филиалов компании | |
18 | 01 Branches:массив |
19 | 02 Branch:структура |
20 | 03 id: целое, ключ |
21 | 03 name: текст |
22 | 03 Address: структура |
23 | 04 region: целое |
24 | 04 city: текст |
// Общий список сотрудников филиала | |
25 | 03 Persons: массив |
26 | 04 Person:структура |
27 | 05 id: целое, ключ |
28 | 05 family_name: текст |
29 | 05 first_name: текст |
30 | 05 second_name: текст |
// Список подразделений, где работает сотрудник | |
31 | 05 deptIds: массив |
32 | 06 deptId: целое |
// Список подразделений филиала | |
33 | 03 Departments: массив |
34 | 04 Department:структура |
35 | 05 id: целое, ключ |
36 | 05 name: текст |
// Список сотрудников подразделения, с указанием должности | |
37 | 05 Members: массив |
38 | 06 Member: структура |
39 | 07 personId: целое, ключ |
40 | 07 position: целое |
4.2 Трансляция описания данных
Составным элементом технологии документного метода доступа к иерархической базе данных является транслятор, преобразующий текст описания данных в дерево описания данных (ДОД). Для запуска транслятора используется следующая команда:
> credod. exe Sample. txt |
В результате создается файл «Schema. dod».
4.3 Генерация кода С++
Для запуска генератора кода с++ используется следующая команда:
> dod2cpp. exe Sample. dod |
В результате будут сгенерированы следующие файлы и классы с++:
Таблица 2. Генерация кода С++.
Файл | Класс | Базовый класс | Примечание |
Пользовательские классы – генерируются один раз, могут редактироваться вручную для расширения базовой функциональности | |||
CAddress. h | CAddress | x_CAddress | Адрес филиала |
CBranch. h | CBranch | x_CBranch | Филиал |
CBranches. h | CBranches | x_CBranches | Список филиалов |
CDepartment. h | CDepartment | x_CDepartment | Подразделение |
CDepartments. h | CDepartments | x_CDepartments | Список подразделений |
CdeptIds. h | CDeptIds | x_CdeptIds | Список кодов подразделений |
CMember. h | CMember | x_CMember | Сотрудник подразделения |
CMembers. h | CMembers | x_CMembers | Список сотрудников подразделения |
CNIKA_ROOT. h | CNIKA_ROOT | x_CNIKA_ROOT | Корень БД |
CPerson. h | CPerson | x_CPerson | Сотрудник филиала |
CPersons. h | CPersons | x_CPersons | Список сотрудников филиала |
Базовые классы – генерируются заново при каждом изменении схемы, не редактируются | |||
x_CAddress. h | x_CAddress | Structure | Адрес филиала |
x_CBranch. h | x_CBranch | Structure | Филиал |
x_CBranches. h | x_CBranches | Array | Список филиалов |
x_CDepartment. h | x_CDepartment | Structure | Подразделение |
x_CDepartments. h | x_CDepartments | Array | Список подразделений |
x_CdeptIds. h | x_CDeptIds | Array | Список кодов подразделений |
x_CMember. h | x_CMember | Structure | Сотрудник подразделения |
x_CMembers. h | x_CMembers | Array | Список сотрудников подразделения |
x_CNIKA_ROOT. h | x_CNIKA_ROOT | Structure | Корень БД |
x_CPerson. h | x_CPerson | Structure | Сотрудник филиала |
x_CPersons. h | x_CPersons | Array | Список сотрудников филиала |
Общие файлы – генерируются заново при каждом изменении схемы, не редактируются | |||
Sample. cpp | нет | Фабрика объектов | |
Sample. h | нет | Служебные заголовки | |
UserClasses. h | нет | Пользовательские классы |
Ниже следуют образцы сгенерированного кода в файлах «CPerson. h» и «x_CMember. h»:
Таблица 3. Файл «CPerson. h»
1 | /* |
2 | CPerson. h - класс для вершины "Person". |
3 | |
4 | Этот файл генерируется только один раз. Вы можете редактировать этот файл. |
5 | */ |
6 | #ifndef _CPERSON_H_ |
7 | #define _CPERSON_H_ |
8 | |
9 | #include "Sample. h" |
10 | #include "x_CPerson. h" |
11 | |
12 | _SAMPLE_BEGIN // namespace |
13 | _DATABASE_USING // promote database namespace into schema namespace |
14 | |
15 | class SAMPLE_API CPerson: |
16 | public x_CPerson |
17 | { |
18 | // Сюда можно добавлять переменные и функции. |
19 | }; |
20 | _SAMPLE_END // namespace |
21 | #endif // _CPERSON_H_ |
Таблица 4. Файл «x_CMember. h»
1 | /* |
2 | x_CMember. h - базовый класс для вершины 38 "Member". |
3 | |
4 | Этот файл автоматически генерируется заново при каждом изменении ДОД. |
5 | Не следует редактировать этот файл вручную. |
6 | */ |
7 | #ifndef _X_CMEMBER_H_ |
8 | #define _X_CMEMBER_H_ |
9 | |
10 | #include "Sample. h" |
11 | |
12 | _SAMPLE_BEGIN // namespace |
13 | _DATABASE_USING // promote database namespace into schema namespace |
14 | |
15 | class SAMPLE_API x_CMember: public Structure { |
16 | public: |
17 | _DATABASE Terminal& personId(){return *(_DATABASE Terminal*) structElement(0,Pointer::dispUpdate);} |
18 | _DATABASE Terminal& position(){return *(_DATABASE Terminal*) structElement(1,Pointer::dispUpdate);} |
19 | |
20 | enum {dodNum = 38}; |
21 | }; |
22 | |
23 | _SAMPLE_END // namespace |
24 | #endif // _X_CMEMBER_H_ |
4.4 Сборка библиотеки Sample. dll из сгенерированных классов
Из сгенерированных классов собирается библиотека Sample. dll. В проект Sample. dsp включается один сгенерированный файл Sample. cpp. В параметрах проекта следует определить макрос SAMPLE_EXPORTS.
Библиотека Sample. dll экспортирует две точки входа:
· Точка входа «ObjectProperties» – ДОД на памяти, в виде таблицы свойств. В таблице свойств имеется по одной строке для каждой вершины ДОД. Таблица индексируется ДОД-номером вершины.
· Точка входа «ObjectFactory» – фабрика объектов. Эта функция используется сервисной библиотекой Database. dll для создания в памяти экземпляров сгенерированных классов.
Далее собирается ваш прикладной проект. В него следует включить две библиотеки:
· Sample. dll - сгенерированный код для доступа к БД. Использует пространство имен по имени файла ДОД, например: «Sample».
· Database. dll - сервисная библиотека. Использует фиксированное пространство имен "_db".
4.5 Пример прикладной программы на С++
Следующая прикладная программа на языке С++ записывает в базу данных список сотрудников филиала:
Таблица 5. Пример программы на С++ в файле «Test1.cpp».
1 | #include <string> |
2 | using namespace std; // Пространство имен библиотеки STL |
3 | |
4 | |
5 | #include "UserClasses. h" // Сгенерированные классы |
6 | |
7 | _SAMPLE_USING // Пространство имен схемы |
8 | _DATABASE_USING // Пространство имен библиотеки Database. dll |
9 | |
10 | Database db; // Глобальный объект – БД |
11 | |
12 | long main(long argc, char **argv) |
13 | { |
14 | // Подключение к БД |
15 | db.connect( |
16 | "Sample. dod", // Файл описания данных |
17 | "1.tre", // Файл данных |
18 | 's', // Уничтожить файл данных и создать заново |
19 | _SAMPLE ObjectProperties, // Таблица свойств в файле Sample. cpp |
20 | _SAMPLE ObjectFactory, // Файбрика объектов в файле Sample. cpp |
21 | (Structure**)&dbRoot, |
22 | Database::mode_tree |
23 | ); |
24 | |
25 | // Создание списка сотрудников для филиала |
26 | long branchId = 10; // Код филиала |
27 | CPersons &a = dbRoot->Branches()[branchId].Persons(); |
28 | |
29 | // Добавление двадцати сотрудников |
30 | for(long index=0; index<20; index++) |
31 | { |
32 | // Поиск или создание сотрудника с заданным индексом. |
33 | // Счетчик использования после оператора [] увеличивается. |
34 | CPerson &str = a[index]; |
35 | |
36 | // Фамилия «Иванов 1-й», «Иванов 2-й»,... |
37 | char buf[10]; |
38 | sprintf(buf,"%d", index); |
39 | str. family_name().set((string)"Иванов_" + buf + "-й"); |
40 | |
41 | // Имя и отчество |
42 | first_name. set("Иван"); |
43 | second_name. set("Иванович"); |
44 | |
45 | /* |
46 | Уменьшить счетчик использования для сотрудника. |
47 | При нулевом счетчике использования, элемент сохраняется в БД |
48 | и удаляется из памяти |
49 | */ |
50 | str->ReleaseRef(); |
51 | } |
52 | } |
4.6 Пример программы на Visual Basic
Следующая программа на языке Visual Basic распечатывает списки сотрудников по филиалам и подразделениям:
Таблица 6. Пример программы на Visual Basic в файле «Module1.bas».
1 | ' Определение переменных |
2 | Dim db As dbcomlib. Database |
3 | Dim dbRoot As dbcomlib. Structure |
4 | dim branch as dbcomlib. Structure |
5 | dim department as dbcomlib. Structure |
6 | dim person as dbcomlib. Structure |
7 | dim info as dbcomlib. Structure |
8 | |
9 | sub main |
10 | |
11 | ' Подключение к БД |
12 | Set db = New dbcomlib. Database |
13 | db. Connect _ |
14 | "Sample. dod", _ |
15 | " 1.tre", _ |
16 | "Sample. dll", _ |
17 | "s" |
18 | |
19 | ' Получение корня БД |
20 | Set dbRoot = db. Root |
21 | |
22 | ' Цикл по филиалам |
23 | for each branch in dbRoot. Branches |
24 | |
25 | ' Цикл по подразделениям |
26 | for each department in branch. Departments |
27 | |
28 | ' Цикл по сотрудникам подразделения |
29 | for each person in department. Persons |
30 | |
31 | ' Информация о сотруднике филиала |
32 | set info = branch. persons(person. personId) |
33 | |
34 | ' Распечатка информации о сотруднике: |
35 | |
36 | ' Код сотрудника и должность в данном подразделении |
37 | Debug. Print person. personId, person. position |
38 | |
39 | ' Фамилия, имя и отчество из общего списка сотрудников филиала |
40 | Debug. Print info. family_name Debug. Print info. first_name, info. second_name |
41 | |
42 | next person |
43 | |
44 | next department |
45 | |
46 | next branch |
47 | |
48 | end sub |
5 Сервисная библиотека Database. dll
Реализация документного метода доступа заключается в сервисной библиотеке Database. dll. В ней содержатся следующие классы:
Класс | Базовый класс | Описание |
Array | Vertex, Cash | Массив |
ArrayIterator | нет | Итератор массива |
Cash | нет | Кэш массива |
Database | нет | База данных |
Pointer | нет | Указатель в БД |
SimpleValue | нет | Типизированное значение |
Structure | Vertex | Структура |
Terminal | Vertex, SimpleValue | Терминальная вершина |
Vertex | нет | Вершина любого типа |
5.1 Типы вершин в БД Ника
В БД Ника имеются следующие типы вершин:
· Структура – может иметь несколько разнотипных элементов, но не более чем по одному экземпляру для каждого описанного типа элемента.
· Массив – может иметь много однотипных элементов. Элементы массива отличаются ключом.
· Терминальная вершина – не имеет подчиненных вершин, зато может хранить одно простое значение:
o Терминальная вершина может быть элементом массива и в этом случае она хранит ключ.
o Терминальная вершина может быть ключевым элементом структуры и в этом случае она хранит ключ данной структуры в массиве структур.
o Терминальная вершина может быть простым элементом структуры и в этом случае она хранит простое данное.
5.2 Состояние вершины в памяти
Состояние вершины в памяти характеризуется комбинацией следующих флагов:
vertexLoaded | Загружена из БД |
vertexChanged | Признак изменения вершины |
vertexSubtreeChanged | Признак изменения поддерева |
vertexDeleted | Помечена для удаления из БД |
vertexKilled | В процессе утилизации |
На следующем рисунке показаны возможные переходы вершины из одного состояния в другое:
Рисунок 1. Жизненный цикл вершины в памяти.
![]() |
5.3 Структурные вершины
Корень БД считается структурной вершиной. Для корня генерируется класс со специальным именем «CNIKA_ROOT». Адрес этой структуры возвращается прикладной программе при открытии БД. Поскольку структура вершин в памяти растет из одного места, то каждая вершина БД может одновременно находиться в памяти не более чем в одном экземпляре.
Доступ к вершинам верхнего уровня и вложенным структурам начинается от корня БД:
27 | CPersons &a = dbRoot->Branches()[branchId].Persons(); |
Здесь круглые скобки после «Branches» означают доступ к элементу «Branches» типа «CBranches» структуры «CNIKA_ROOT». Квадратные скобки далее есть оператор «[]», определенный в классе CBranches для поиска либо создания элемента массива. Оператор «[]» в данном примере возвращает объект «CBranch»:
В файле CBranches. h: |
CBranch &operator[](const long key) |
{return *(CBranch*) arrayElement(key, Pointer::dispUpdate);} |
Наконец в цитированной строке 27 используется запись «.Persons()», для доступа к элементу структуры «CBranch» – массиву «CPersons». На этом примере показано, как одной строкой кода достигается спуск на три уровня БД, с созданием элемента массива.
Заметим, что еще короче, без использования квадратных скобок, записывается поиск элемента массива по ключу:
iterator_Cbranches &it = dbRoot->Branches(branchId); // Поиск по ключу |
if (it. ok()) // Проверка существования элемента |
... // Обработка элемента |
В каждой структуре имеется набор функций с именами, совпадающими с именами элементов структуры. Например, в структуре «CMember» имеются функции для доступа к элементам «personId» и «position»:
17 | _DATABASE Terminal& personId(){return *(_DATABASE Terminal*) structElement(0,Pointer::dispUpdate);} |
18 | _DATABASE Terminal& position(){return *(_DATABASE Terminal*) structElement(1,Pointer::dispUpdate);} |
Элементы структур создаются в памяти в два этапа:
· На первом этапе структура загружается из БД. При загрузке каждой структуры из БД, вместе с ней рекурсивно загружаются и все вложенные структуры, до массивов.
· На втором этапе новые элементы структуры создаются в памяти, если прикладная программа к ним обращается. Однако это не значит, что пустые элементы структуры будут сохраняться в БД. Для сохранения вершины в БД необходимо либо записать значение, либо создать элемент массива в поддереве данной вершины. См. ниже п. 5.7 «Сохранение изменений».
5.4 Массивы
Загрузка в память. Массивы можно загружать в память либо сразу, либо загружать элементы поочередно. Первый способ удобен для небольших массивов. Для полной загрузки массива в память можно использовать функцию Vertex::Reload():
a. Reload(Vertex::completeLoad);
Работа с загруженным массивом ничем не отличается от работы с незагруженным массивом, но итератор массива не будет использовать процесс в БД.
Создание элемента массива. Для создания нового элемента массива в памяти можно использовать оператор []:
34 | CPerson &str = a[index]; |
Новый элемент автоматически помечается как измененный и впоследствии будет отписан в БД при сохранении изменений.
Поиск. В БД НИКА любой массив обязательно принадлежит некоторой структуре. Для поиска элемента массива с заданным ключом можно указать ключ в функции доступа к элементу объемлющей структуры. При этом создается итератор, который нужно будет удалить при помощи функции Database::Trash().
5.5 Итераторы
Для просмотра массива рекомендуется использовать итераторы. Типизированные итераторы генерируются для каждого массивного класса. Семантика итераторов несколько отличается от Standard Template Library, для того чтобы избежать создания лишних процессов в БД.
Итераторы поддерживают операторы «*», «->», а также префиксные и постфиксные формы операторов «++» и «--»:
Префиксная форма: ++it, --it.
Постфиксная форма: it++, it--.
Префиксная форма оператора «++» или «--» более эффективна, поскольку семантика постфиксной формы включает шаги, обычно остающиеся невидимыми для программиста. Например если использовать оператор «it++» для продвижения итератора вперед по массиву, то «за сценой» происходят следующие действия
· Создание копии итератора, с копированием процесса БД.
· Продвижение итератора.
· Возвращение исходной копии итератора.
· Удаление процесса БД, без его использования.
Поэтому для продвижения итератора рекомендуется использовать префиксную форму оператора: «++it».
5.6 Терминальные вершины
Терминальные вершины хранят значения: ключи и данные в вершинах БД. Для значений имеется базовый класс «SimpleValue». Значение хранится в памяти в одном из следующих форматов:
· строка – тип «string» из библиотеки Standard Template Library(STL);
· целое число 4 байта
· плавающее число 8 байтов.
Класс «SimpleValue» поддерживает простейшие преобразования типов. При записи в БД тип приводится к заданному в ДОД.
5.7 Сохранение изменений
Обычно основанием для записи в БД является создание элемента массива, либо запись значения в терминальную вершину. Эти действия отслеживаются автоматически, поэтому обычно для сохранения изменений в БД, достаточно будет вызвать в конце работы прикладной программы функцию Database::Save().
При помощи функции Vertex::setChanged() можно пометить вершину как измененную. Только так можно записать в БД вершину без значения и без подчиненных вершин.
6 COM-надстройка DbCom. dll
Для доступа к хранимым документам из прикладных программ на языке Visual Basic имеется библиотека DbCom. dll, которая используется в сочетании с описанной выше сервисной библиотекой Database. dll. В библиотеку DbCom. dll входят следующие интерфейсы:
COM-интерфейс в библиотеке DbCom.dll | Реализуется классом c++ в библиотеке DbCom.dll | Используется класс c++ в библиотеке Database.dll | Описание |
IArray | DbArray | Array | Массив |
IIterator | DbIterator | ArrayIterator | Итератор массива |
IDatabase | DbDatabase | Database | База данных |
ITerminal | DbTerminal | Terminal | Терминальная вершина |
IStructure | DbStructure | Structure | Структура |
IVertex | DbVertex | Vertex | Вершина любого типа |
6.1 Интерфейс IVertex
Интерфейс IVertex есть базовый интерфейс для всех типов вершин. Объекты для структурных, массивных и терминальных типов вершин в библиотеке DbCom. dll поддерживают интерфейс IVertex. Каждый из классов DbStructure, DbArray и DbTerminal реализует один из интерфейсов IStructure, IArray и ITerminal и "агрегирует" в себе объект типа DbVertex, который реализует интерфейс IVertex.
Имеется два способа доступа к интерфейсу IVertex в программе на VB.
Первый способ. Переменной типа "dbcomlib. Vertex" можно присвоить объектное значение для любого типа вершины:
Dim v as dbcomlib. Vertex
set v = MyStruct ' Структура
set v = MyArray ' Массив
set v = MyTerminal ' Терминальная
Второй способ. Массивы и терминальные типы вершин обладают свойством "Vertex", а структуры обладают свойством "zzVertex". Эти свойства возвращают интерфейс IVertex, свойствами и методами которого можно в этом случае пользоваться без дополнительной переменной:
s = MyStruct. zzVertex. dodName ' Структура
if MyArray. Vertex. exists Then ' Массив
type = MyTerminal. Vertex. dodType ' Терминальная
6.2 Срок жизни документа в памяти
Для правильного и эффективного программирования с помощью библиотеки DbCom. dll, важно понимать, что документы загружаются из БД и могут удерживаться в памяти до конца срока жизни COM-объекта для данного документа, но не позднее срока жизни COM-объекта для более крупного документа. При удалении каждого документа из памяти, вместе с ним удаляются и все поддокументы.
Рассмотрим гипотетический пример, в котором элементы массива суммируются и сумма записывается в заданный элемент того же массива; кроме того в каждом элементе проставляется текущая дата и время:
Dim e as Object, e2 as Object
Dim sum as long ' Сумма элементов массива
' Цикл по массиву, с суммированием.
' В каждой итерации новый элемент загружается в память из БД
For Each e In MyStruct. MyArray
' Сумма накапливается
sum = sum + e. MyNumber
' Дата элемента изменяется в памяти.
e. MyDate = Now()
' Объект присваивается другой переменной, при этом
' счетчик использования элемента увеличивается.
if e. MyFunction = "sum" then
set e2 = e
end if
' В конце итерации каждый элемент сохраняется в БД
' и удаляется из памяти, за исключением элемента,
' который удерживается переменной "e2"
Next str
' Сумма записывается в заданный элемент
e2.MyResult = sum
' Элемент сохраняется в БД и удаляется из памяти
set e2 = nothing
6.3 Сборка мусора
Объект DbVertex, который принадлежит библиотеке DbCom. dll, связан взаимно однозначной двусторонней ссылкой с объектом типа "Vertex", который принадлежит библиотеке Database. dll.
В случае удаления из памяти объекта "Vertex", например, с помощью функции IVertex::Trash(), в памяти остается "мертвый" объект DbVertex, с нулевой привязкой к библиотеке Database. dll. "Реанимировать" мертвый объект нельзя. Он удаляется из памяти по обычным правилам сборки мусора для COM-объектов, когда прикладная программа на язке Visual Basic обнулит все ссылки на него. При повторной загрузке той же вершины в память из БД в программе на Visual Basic, для нее будет создана новая пара объектов: объект из библиотеки Database. dll и объект из библиотеки DbCom. dll.
Для "мертвых" объектов свойство "exists" всегда возвращает FALSE:
v. Trash ' Удаление вершины из памяти
...
if v. exists then ' Проверка существования вершины
6.4 Интерфейс IStructure
Интерфейс IStructure переопределяет методы интерфейса IDispatch для прозрачного доступа к элементам структуры. Visual Basic автоматически пользуется интерфейсом IDispatch для доступа к свойствам и методам структур, отсутствующим в определении интерфейса IStructure. Ключи и значения передаются из VB в библиотеку DbCom. dll как параметры метода IDispatch::Invoke. Все это происходит скрыто от программиста и лаконично записывается на Visual Basic. Следующие примеры показывают возможности работы со структурами из VB:
set obj = MyStruct. MyArray("ключ") ' Доступ к массиву
MyStruct. MyField = "abc" ' Присвоение значения
s = MyStruct. MyField ' Чтение значения
При использовании длинных цепочек доступа промежуточные объекты создаются и уничтожаются автоматически:
' Длинная цепочка доступа, с чтением значения из вершины "MyField"
s = MyStruct. MyArray1("ключ1").MyArray2("ключ2").MyField
На массивных уровнях можно указывать ключи и режим создания:
' Длинная цепочка доступа, с созданием ключей
' на массивных уровнях и с записью значения в вершину "MyField"
MyStruct. _
MyArray1("ключ1", dispUpdate). _
MyArray2("ключ2", dispUpdate). _
MyField = "abc"
Для того чтобы не провоцировать путаницу свойств интерфейса IStructure с элементами структуры, для свойств используется префикс "zz":
' Префикс "zz" используется для свойств структуры:
set v = MyStruct. zzVertex ' Получить интерфейс IVertex
key = MyStruct. zzKey ' Прочесть ключ структуры
' Доступ к элементам структуры, без использования префикса "zz":
s = MyStruct. Key ' Доступ к элементу "Key"
s = MyStruct. MyKey ' Доступ к элементу "MyKey"
6.5 Интерфейс IArray
Интерфейс для массивного типа вершин. Массив поддерживает свойства коллекции Visual Basic:
' Цикл по массиву
For Each element In MyStruct. MyArray
Debug. Print element. MyField
Next str
Для доступа к элементам массива по ключу имеются методы IArray::Item и IArray::Add. Метод IArray::Item используется для массива по умолчанию, если имя метода опущено:
set element = MyArray("ключ")
' эквивалентно:
set element = MyArray. Item("ключ")
Метод IArray::Add используется для создания элементов массива:
set element = MyArray. Add("ключ") ' Поиск или создание элемента
set element = MyArray. Add("ключ", dispReplace) ' Замена существующего элемента
6.6 Интерфейс IIterator
Интерфейс для итератора массива. Итераторы используются автоматически внутри Visual Basic для выполнения циклов по массиву. Программисту на Visual Basic не следует явно пользоваться итераторами:
' Цикл по массиву
Dim str As dbcomlib. Structure
...
For Each str In MyArray
Debug. Print str. Text
Next str
6.7 Интерфейс ITerminal
Интерфейс ITerminal используется для терминальных вершин. Терминальные вершины поддерживают стандартное свойство "Value" и могут быть использованы всюду, где Visual Basic ожидает простую, необъектную переменную: в левой части оператора присваивания, в выражениях и в параметрах вызова функций. В то же время терминальная вершина есть объект со своими свойствами и методами:
' Терминальная вершина используется как обычная, необъектная переменная
MyStruct. MyField = "abc" ' В левой части присваивания
s = "abc" & MyStruct. MyNumber ' В выражении
MyArray(MyStruct. MyField) ' В качестве ключа массива
' Инициализация объектной переменной
set t = MyStruct. MyField
' Объект со значением используется как обычная, необъектная переменная
t = "abc" ' В левой части присваивания
s = "abc" & t ' В выражении
MyArray(t) ' В качестве ключа массива
' Используется метод ITerminal::Delete()
t. Delete() ' Значение обнуляется и вершина помечается для удаления
Терминальной вершина может поддерживать признаки атрибута, если это указано в ДОД в следующем виде:
// Пометки атрибута в ДОД:
- i[m][w] // Имя атрибута совпадает с именем вершины
- i[m][w]=Атрибут1 // Задано имя атрибута без кавычек
- i[m][w]="Атрибут 1" // Задано имя атрибута в кавычках
Флаги:
i - атрибут
m - многозначный
w - индексировать по каждому слову
Примеры:
// Однозначный атрибут; имя атрибута совпадает с именем вершины
04 MyField: текст, i
// Многозначный атрибут; имя атрибута совпадает с именем вершины
04 MyField: текст, im
// Многозначный атрибут с индексированием по каждому слову,
// имя атрибута указано в кавычках
04 MyText: текст, imw = "Все слова"
Замечание: информация об атрибутах в данной реализации библиотеки DbCom. dll только хранится, но никак не обрабатывается.
7 Литература
1. Системы управления базами данных и знаний: Справ. изд. / , , и др.; Под ред. . М.: Финансы и статистика, 1991.
2. Visual Architect and THINK Class Library Guide. Symantec Corporation, 1994.
3. , Голоусикова среды хранения объектов над иерархической СУБД. Сборник трудов ИСА РАН «Развитие безбумажной технологии в организационных системах»/Под редакцией и М.: Эдиториал УРСС, 1999.



