Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Без справочников не обходится ни одна информационная система. Как правило, такие справочники представлены в виде одной либо нескольких таблиц, иногда связанных между собой. Одной из проблем является "неполнота" данных, когда справочник не заполнен по определенным позициям.
Необходимо разработать структуру справочника, который выдает значение "всегда", если нет значения в запрашиваемом узле справочника - должно быть выдано значение из вышестоящего уровня иерархии.
Пример подобной структуры:
|Id | ParentId | Name | Value | ,
где ParentId - ссылка на вышестоящий узел.
Глубина иерархии такого справочника не ограничена, так-же возможно неограниченное разветвление дерева.
Рассмотрим справочник адресов почты сотрудников предприятия.
|Id | ParentId | Name | Value |
|1 | null | Предприятие | Наше предприятие |
|2 | 1 | E-mail | factory@mail.ru |
Условный запрос вида Get({Предприятие="Наше предприятие"}, E-mail) выдаст значение "factory@mail.ru".
Добавим узел дерева справочника - Подразделение="Отдел ИТ" и к нему еще один узел
E-mail="it@mail.ru"
Теперь запрос Get({Предприятие="Наше предприятие", Подразделение="Отдел ИТ"}, E-mail) выдаст значение "bskb@mail.ru". Однако, если нет узла "Подразделение", либо значение не заполнено - значение будет взято из вышестоящего узла.
Если добавить узел дерева "Служба поддержки" и значение support@mail.ru со ссылкой на узел "Подразделение"="Отдел ИТ" - получим адрес службы поддержки, если он не существует - адрес отдела, и так далее выше по иерархии.
Таким образом получаем структуру справочника, который выдает значение "всегда".
Второй пример - интернационализация приложения.
Для интернационализации приложения предлагается следующий подход:
в базе данных хранятся значения Caption и Hint для всех компонентов, используемых в приложении;
при запуске приложения они считываются из БД и заполняются соответствующие свойства компонентов;
для получения значения Caption и Hint запрос к БД делается в виде .
..;
для хранения Caption и Hint используется иерархическая структура справочника, который выдает значение "всегда", если нет значения в запрашиваемом узле справочник - будет выдано значение из вышестоящего уровня иерархии. Глубина иерархии такого справочника не ограничена, так-же возможно неограниченное разветвление дерева.
Пример: Запрос Get(Application.Form1.Component2.Property3) выдаст значение из узла "Application", если нет значений для нижестоящего уровня иерархии,
выдаст значение из узла "Form1" - если есть значение для этого уровня иерархии, и так далее.
Таким образом можно, например, ввести значение Caption="Поиск" для кнопки с Origin="Find" для всего приложения, но для кнопки на форме "Form2" - использовать значение "Искать", а для кнопки "btnFindAll" - - использовать значение "Искать везде".
Такой способ существенно экономит место в БД, так как хранится всего одно общее значение и исключения от него.
Структура таблицы:
CREATE TABLE t_caption_ru
(
id
INT UNSIGNED NOT NULL AUTO_INCREMENT,
parent_id
INT NULL DEFAULT '0',
owner
VARCHAR(255) NOT NULL,
origin
VARCHAR(255) NOT NULL,
caption
VARCHAR(255) NOT NULL,
hint
VARCHAR(255) NOT NULL,
INDEX Индекс 1
(id
)
)
ENGINE=InnoDB
AUTO_INCREMENT=1;
Запрос для получения данных:
SET @origin='Find';
SET @LEVEL1='Application';
SET @LEVEL2='Form1';
SET @LEVEL3='btnFind';
/* Выдает первое значение, которое не NULL, то есть значение будет всегда, но с разных уровней иерархии */
SELECT COALESCE(t3.caption, t2.caption, t1.caption)
FROM t_caption_ru t1
LEFT JOIN t_caption_ru t2 ON (t2.parent_id=t1.id AND t2.owner @LEVEL22)
LEFT JOIN t_caption_ru t3 ON (t3.parent_id=t2.id AND t3.owner @LEVEL33)
WHERE
(t1.owner = @LEVEL1 AND t1.origin = @origin) or
(t2.origin = @origin) or
(t3.origin = @origin)