Перед тем как начать, я хочу сказать пару слов. Хотя все
что я пишу, и выглядит, как некие абстрактные размышления, я описываю совершенно
конкретный подход и совершенно конкретную реализацию генератора информационных
систем. Не больше, но и не меньше. Сегодня этот генератор решает целый ряд
задач, и мы сами его активно используем в работе. Поэтому, я прошу не обижаться
тех, кто пишет мне, в общем-то, очень правильные, но скорее теоретические вещи.
Я рассказываю, как сделано и какие преимущества можно получить и, к сожалению, у
меня просто нет времени на обсуждение теорий.
Сегодня будет достаточно сложный выпуск.
Сложный, хотя бы потому, что нам надо опуститься на самый
нижний уровень. Т.е. прямо на уровень базы данных.
Для начала вспомним одну важную вещь. Для того, чтобы
существовать и развиваться большая система должна быть достаточно хорошо
стандартизирована. Мы постараемся довести эту стандартизацию до максимума. И
заведем единственную таблицу в базе данных, которая станет точкой входа во всё
пространство данных. Эта таблица будет носить название
Instanceи содержать идентификаторы
документов, которые охраняться в системе. Т.е. что бы за документ мы не
погрузили в систему его идентификатор всегда будет храниться в таблице Instance. Надеюсь, это не очень сильно нарушает
общность наших рассуждений. В принципе для начала нам достаточно, чтобы кроме
идентификатора у документа было еще дно поле, которое говорит, где нам дальше
искать информацию. Это поле назовем Кодом типа объекта (ObjType).
Алгоритм доступа будет примерно таким. Берем идентификатор документа, смотрим
какого он типа и активизируем компонент (объектную библиотеку и т.п.), который
реализует документ данного типа, дальше компонент сам обеспечивает работу с
документом. Какая-никакая а стандартизация.
Но это как-то не очень красиво смотрится, к тому же у нас
есть еще пара полезных идей уже на этой стадии.
Первая состоит в том, что даже на самом абстрактном уровне
документу полезно было бы дать хоть какое-то видимое имя. А почему только
документу? Любая строка должна иметь видимое представление.
Вторая более сложная. Предположим, что один документ может
быть зависимым ( прицепленным) к другому документу. Например, договор зависит от
клиента. В этом случае, скажем, удаление информации о клиенте может приводить и
к удалению информации о договоре.
Третья тоже сложная. Она связана с жизненным циклом
существования документа. В каждый конкретный момент документ может находиться в
некотором состоянии. Пока мы оставим место только под идентификатор состояния.
И теперь еще одно соображение. Очень хочется, чтобы
идентификатор был действительно уникальным. Т.е. в ситуации с
многопользовательской системой нам было бы гарантировано, что клиент может
создать запись с каким-то идентификатором, и не возникнет конфликт по этому
идентификатору.
Исходя из вышеизложенного получаем следующие требования.
ТС1-5 Все идентификаторы в базе данных реализуются
при помощи механизма глобально уникальных идентификаторов (GUID)
ТС1-6 Все документы регистрируются в единой
таблице
ТС1-7 Документ должен имеет видимое (строковое)
представление, которое может быть использовано для отображения в списке.
ТС1-8 Каждая строка документа должна иметь видимое
(строковое) представление, которое может быть использовано для отображения в
списке, при установке ссылки на строку и т.п.
TC1-9 Алгоритм определения
имя поля для хранения идентификатора должен быть фиксирован для всей базы
данных.
Мы реализовали это требование следующим образом: имя поля
идентификатора формируется как имя таблицы с добавлением пары букв
ID в конце. Можно было бы поступить проще. И назвать
все поля идентификаторы просто ID. Кому что нравится.
TM4 Метаданные должны
содержать описание жизненного цикла (множество состояний и допустимых переходов)
документа.
TM5 Метаданные должны
содержать информацию о множестве полей строки, которые формируют краткое
представление строки.
Вот теперь самое время показать, как описывается таблица
Instance.
CREATE TABLE Instance (
InstanceID
uniqueidentifier NOT NULL ,
Name varchar (255)
NULL ,
ObjType varchar (255) NULL ,
OwnerPartName varchar (255)
NULL ,
OwnerRowID uniqueidentifier
NULL ,
status uniqueidentifier NULL
)
И сразу приведем пример сегмента базы данных под документ.
Документ реализует каталог. И состоит из общего описания каталога, раздела,
описывающего структуру папок, и списка ярлыков, которые лежат в папке.
Я думаю, до сих пор не ясно, что значит понятие «сегмент
базы данных» и в свете этого что означает требование ТС1-3 из предыдущего
выпуска. Идея крайне проста. Если мы описываем структуру документа, то все
таблицы, которые реализуют документ, хранят только информацию для документов
такого типа. Множество этих таблиц и называется сегментом. Пример. У нас 10
справочников одинаковой структуры. Каждый хранит единственное поле – Название.
Но мы все равно будем иметь в базе данных 10 таблиц. Каждая таблица реализует
один справочник. В зависимости от описания мы можем иметь от 1 (все справочники
лежат являются разделами одного документа) до 10 (каждый справочник лежит в
своем документе) логических сегментов в базе данных. Т.е. соответствие между
типом документа и сегментом базы данных строго однозначное. Основное правило
такое сильные связи, т. е. внешние ключи можно использовать только внутри
сегмента, или если они построены к таблице Instance.
Остальные связи можно контролировать только логически. Почему я так думаю –
расскажу потом.
Итак смотрим на целый документ.
CREATE TABLE InfoStoreDef (
InstanceID uniqueidentifier
NULL , -- это ссылка на документ (сильная связь)
InfoStoreDefiduniqueidentifier NOT NULL , -- это идентификатор
раздела Описание
TheGroup uniqueidentifier
NULL , -- это ссылка на группу пользователей ( слабая связь)
Name varchar (255) NULL ,
-- это название
InfoStoreType int NULL
, -- это тип каталога ( личный, общий, групповой) перечисление,, или
ENUM
TheUser uniqueidentifier
NULL --это владелец личного каталога ссылка на пользователя (слабая
связь)
)
CREATE
TABLE Folder (
InstanceID uniqueidentifier NULL , -- это ссылка на документ
(сильная связь)
Folderid uniqueidentifier NOT NULL , -- это
идентификатор раздела Папка
ParentRowid uniqueidentifier NULL , -- это реализация
древовидной (иерархической) структуры
Name varchar (255) NULL- Это
название папки
)
CREATE
TABLE Shortcut (
ParentStructRowID uniqueidentifier NOT NULL , -- Это
ссылка на родительский раздел
Shortcutid uniqueidentifier NOT NULL , -- это
идентификатор строки в разделе Ярлык
DocItem uniqueidentifier NULL -- это ссылка на документ
)
Сильные связи дополнительно
подкреплены низкоуровневым механизмом проверки целостности.