А разве группа не может быть представителем группы? Группа групп, например. Множество множеств. Класс классов. Может. И чем больше мы уходим в абстракт, тем более "может". В пределе "все" — есть "что-то", и каждое "что-то" состоит из других "что-то".
Насколько я понял терминологию, объект — это нечто, существующее в реальности. Модель объекта — это представление реального объекта в рамках моделируемой предметной области. Типы объектов — это некоторая классификация реальных объектов по общим признакам. Объект реального мира может принадлежать к различным типам объектов в зависимости от применяемой классификации. Свойство (признак, атрибут) — некоторая значимая (имеет определенное значение) характеристика объекта. Элемент — часть объекта. Структура (конструкция) — множество различных элементов объекта в совокупности представляющая объект. Объект может быть разделен на элементы различными способами, каждому такому разделению соответствует своя конструкция.
У меня складывается ощущение что вы одновременно говорите за модель предметной области и за мета-модель, в которой "живет" модель предметной области. Если разделить данные на две группы: описание самих объектов (их атрибутов, конструкций и элементов) и описание мета-данных (типов объектов, атрибутов, классов объектов, типов конструкций и типов элементов), то у меня получается примерно вот такая структура:
Скрытый текст
DROP TABLE IF EXISTS struct_elem, elem_class, elem, struct_class, struct_obj, struct;
DROP TABLE IF EXISTS obj_attr, attr_class, obj_class, attr, obj;
DROP TABLE IF EXISTS meta_struct_elem, meta_elem, meta_struct;
DROP TABLE IF EXISTS meta_classifier_attr, meta_classifier;
DROP TABLE IF EXISTS meta_obj_attr, meta_attr, meta_obj;
--
-- Мета данные для объектов.
--
CREATE TABLE meta_obj (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Реестр типов объектов (деревья, люди, ...)';
CREATE TABLE meta_attr (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Реестр типов атрибутов (высота, имя, ...)';
CREATE TABLE meta_obj_attr (
obj INT(10) UNSIGNED NOT NULL,
attr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (obj, attr),
CONSTRAINT meta_obj_attr_to_obj FOREIGN KEY (obj) REFERENCES meta_obj (id)
ON DELETE CASCADE,
CONSTRAINT meta_obj_attr_to_attr FOREIGN KEY (attr) REFERENCES meta_attr (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка типов атрибутов к типам объектов (высота для деревьев, имена для людей)';
--
-- Мета данные для классификатора объектов.
--
CREATE TABLE meta_classifier (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Реестр классов (способов объединения атрибутов объекта для различения экземпляров объектов по значениям атрибутов)';
CREATE TABLE meta_classifier_attr (
class INT(10) UNSIGNED NOT NULL,
attr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (class, attr),
CONSTRAINT meta_classifier_attr_to_class FOREIGN KEY (class) REFERENCES meta_classifier (id)
ON DELETE CASCADE,
CONSTRAINT meta_classifier_attr_to_attr FOREIGN KEY (attr) REFERENCES meta_attr (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка класса к атрибутам, его характеризующим (масса-высота-ширина или долгота-широта)';
--
-- Мета данные для классификатора конструкций.
--
CREATE TABLE meta_struct (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Реестр типов конструкций';
CREATE TABLE meta_elem (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Реестр типов элементов конструкций';
CREATE TABLE meta_struct_elem (
struct INT(10) UNSIGNED NOT NULL,
elem INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (struct, elem),
CONSTRAINT meta_struct_elem_to_struct FOREIGN KEY (struct) REFERENCES meta_struct (id)
ON DELETE CASCADE,
CONSTRAINT meta_struct_elem_to_elem FOREIGN KEY (elem) REFERENCES meta_elem (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка типов элементов к типам конструкций';
--
-- Предметная область (объекты и их свойства).
--
CREATE TABLE obj (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Реестр экземпляров объектов (#1, #2, ...)';
CREATE TABLE obj_class (
obj INT(10) UNSIGNED NOT NULL,
class INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (obj, class),
CONSTRAINT obj_class_to_obj FOREIGN KEY (obj) REFERENCES obj (id)
ON DELETE CASCADE,
CONSTRAINT obj_class_to_class FOREIGN KEY (class) REFERENCES meta_obj (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка экземпляров объектов к типам объектов (#1 - дерево, #2 - человек)';
CREATE TABLE attr (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-- значением атрибута может быть что угодно, включая ссылки на другие объекты; для упрощения - просто некий текст
-- каким образом он обрабатывается - решается на программном уровне, для хранилища главное - хранить значение
value TEXT NULL,
PRIMARY KEY (id)
)
COMMENT = 'Реестр значений атрибутов (#1 - тополь, #2 - 3м)';
CREATE TABLE attr_class (
attr INT(10) UNSIGNED NOT NULL,
class INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (attr, class),
CONSTRAINT attr_class_to_attr FOREIGN KEY (attr) REFERENCES attr (id)
ON DELETE CASCADE,
CONSTRAINT attr_class_to_class FOREIGN KEY (class) REFERENCES meta_attr (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка значений атрибутов к типам (классам) атрибутов (#1 - порода, #2 - высота)';
CREATE TABLE obj_attr (
obj INT(10) UNSIGNED NOT NULL,
attr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (obj, attr),
CONSTRAINT obj_attr_to_obj FOREIGN KEY (obj) REFERENCES obj (id)
ON DELETE CASCADE,
CONSTRAINT obj_attr_to_attr FOREIGN KEY (attr) REFERENCES attr (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка значений атрибутов к экземплярам объектов (порода объекта #1 - тополь';
--
-- Конструкции и элементы.
--
CREATE TABLE struct (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Реестр экземпляров конструкций';
CREATE TABLE struct_obj (
struct INT(10) UNSIGNED NOT NULL,
obj INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (struct, obj),
CONSTRAINT struct_obj_to_struct FOREIGN KEY (struct) REFERENCES struct (id)
ON DELETE CASCADE,
CONSTRAINT struct_obj_to_obj FOREIGN KEY (obj) REFERENCES obj (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка экземпляров конструкций к экземплярам объектов';
CREATE TABLE struct_class (
struct INT(10) UNSIGNED NOT NULL,
class INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (struct, class),
CONSTRAINT struct_class_to_struct FOREIGN KEY (struct) REFERENCES struct (id)
ON DELETE CASCADE,
CONSTRAINT struct_class_to_class FOREIGN KEY (class) REFERENCES meta_struct (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка экземпляров конструкций к типам конструкций';
CREATE TABLE elem (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-- элемент конструкции сам является объектом
obj INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (id),
CONSTRAINT elem_to_obj FOREIGN KEY (obj) REFERENCES obj (id)
ON DELETE CASCADE
)
COMMENT = 'Реестр значений элементов экземпляров конструкций';
CREATE TABLE elem_class (
elem INT(10) UNSIGNED NOT NULL,
class INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (elem, class),
CONSTRAINT elem_class_to_elem FOREIGN KEY (elem) REFERENCES elem (id)
ON DELETE CASCADE,
CONSTRAINT elem_class_to_class FOREIGN KEY (class) REFERENCES meta_elem (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка значений элементов к типам элементов';
CREATE TABLE struct_elem (
struct INT(10) UNSIGNED NOT NULL,
elem INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (struct, elem),
CONSTRAINT struct_elem_to_obj FOREIGN KEY (struct) REFERENCES struct (id)
ON DELETE CASCADE,
CONSTRAINT struct_elem_to_attr FOREIGN KEY (elem) REFERENCES elem (id)
ON DELETE CASCADE
)
COMMENT = 'Привязка значений элементов к экземплярам конструкций';
Сначала заполняются мета-данные, затем описание объектов (хотя объекты можно прописать и без мета-данных к ним). Эта структура позволяет корректно описывать предметную область, но консистентность данных обеспечивается тем, кто их заполняет (программа, человек).
В применении к схеме из самой статьи (с желтыми и зелеными прямоугольниками) что является "структурой", "объектом", "элементом", "типом объектов", "атрибутом"?
Если вы оперируете объектами, а не их атрибутами, то для их представления вполне достаточно ID объекта и его типа/класса. Классические инструменты вполне позволяют это делать, если не закапываться в дебри. Ваша схема из статьи про ЛЭП/трассы/провода/участки очень хорошо укладывается в типичную RDBMS (MySQL в моем случае). Все, что с префиксом "obj" — это таблицы для желтых элементов вашей схемы, с префиксом "ctx" — для синих:
Вот SQL-код для построения структуры и заполнения ее данными:
Скрытый текст
DROP TABLE IF EXISTS ctx_lep_as_trassa, ctx_lep_as_uch, ctx_trassa_as_provod, ctx_trassa_as_uch_tr;
DROP TABLE IF EXISTS ctx_uch_lep_as_uch_tr, ctx_provod_as_uch_prov, ctx_uch_tr_as_uch_prov, ctx_lep_as_uch_tr;
DROP TABLE IF EXISTS obj_lep, obj_trassa, obj_provod, obj_uch_lep, obj_uch_trassa, obj_uch_provod;
— — Objects (реестры объектов)
— CREATE TABLE obj_lep (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'ЛЭП';
CREATE TABLE obj_trassa (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Трасса';
CREATE TABLE obj_provod (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Провод';
CREATE TABLE obj_uch_lep (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Участок ЛЭП между опорами';
CREATE TABLE obj_uch_trassa (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Участок трассы между опорами';
CREATE TABLE obj_uch_provod (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Участок провода между опорами';
— — Contexts (контексты/конструкции)
— CREATE TABLE ctx_lep_as_trassa (
lep INT(10) UNSIGNED NOT NULL,
trassa INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (lep, trassa),
CONSTRAINT ctx_lep_as_trassa_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_lep_as_trassa_to_trassa FOREIGN KEY (lep) REFERENCES obj_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 1: ЛЭП как трассы';
CREATE TABLE ctx_lep_as_uch (
lep INT(10) UNSIGNED NOT NULL,
uch INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (lep, uch),
CONSTRAINT ctx_lep_as_uch_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_lep_as_uch_to_uch FOREIGN KEY (uch) REFERENCES obj_uch_lep (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 2: ЛЭП как участки';
CREATE TABLE ctx_trassa_as_provod (
trassa INT(10) UNSIGNED NOT NULL,
provod INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (trassa, provod),
CONSTRAINT ctx_trassa_as_provod_to_trassa FOREIGN KEY (trassa) REFERENCES obj_trassa (id)
ON DELETE CASCADE,
CONSTRAINT ctx_trassa_as_provod_to_provod FOREIGN KEY (provod) REFERENCES obj_provod (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 3: трасса как провода';
CREATE TABLE ctx_trassa_as_uch_tr (
trassa INT(10) UNSIGNED NOT NULL,
uch_tr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (trassa, uch_tr),
CONSTRAINT ctx_trassa_as_uch_tr_to_trassa FOREIGN KEY (trassa) REFERENCES obj_trassa (id)
ON DELETE CASCADE,
CONSTRAINT ctx_trassa_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 4: трасса как участки трассы';
CREATE TABLE ctx_uch_lep_as_uch_tr (
uch_lep INT(10) UNSIGNED NOT NULL,
uch_tr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (uch_lep, uch_tr),
CONSTRAINT ctx_uch_lep_as_uch_tr_to_uch_lep FOREIGN KEY (uch_lep) REFERENCES obj_uch_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_uch_lep_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 5: участок ЛЭП как участок трассы';
CREATE TABLE ctx_provod_as_uch_prov (
provod INT(10) UNSIGNED NOT NULL,
uch_prov INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (provod, uch_prov),
CONSTRAINT ctx_provod_as_uch_prov_to_provod FOREIGN KEY (provod) REFERENCES obj_provod (id)
ON DELETE CASCADE,
CONSTRAINT ctx_provod_as_uch_prov_to_uch_prov FOREIGN KEY (uch_prov) REFERENCES obj_uch_provod (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 6: провод как участок провода';
CREATE TABLE ctx_uch_tr_as_uch_prov (
uch_tr INT(10) UNSIGNED NOT NULL,
uch_prov INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (uch_tr, uch_prov),
CONSTRAINT ctx_uch_tr_as_uch_prov_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE,
CONSTRAINT ctx_uch_tr_as_uch_prov_to_uch_prov FOREIGN KEY (uch_prov) REFERENCES obj_uch_provod (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 7: участок трассы как участок провода';
CREATE TABLE ctx_lep_as_uch_tr (
lep INT(10) UNSIGNED NOT NULL,
uch_tr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (lep, uch_tr),
CONSTRAINT ctx_lep_as_uch_tr_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_lep_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 8: ЛЭП как участок трассы';
— — Данные (объекты)
— INSERT INTO obj_lep VALUES (1);
INSERT INTO obj_trassa VALUES (1), (2);
INSERT INTO obj_provod VALUES (1), (2);
INSERT INTO obj_uch_lep VALUES (1), (2);
INSERT INTO obj_uch_trassa VALUES (1), (2), (3);
INSERT INTO obj_uch_provod VALUES (1), (2), (3);
— — Данные (связи в контекстах)
— INSERT INTO ctx_lep_as_trassa VALUES (1, 1), (1, 2);
INSERT INTO ctx_lep_as_uch VALUES (1, 1), (1, 2);
INSERT INTO ctx_trassa_as_provod VALUES (2, 1), (2, 2);
INSERT INTO ctx_trassa_as_uch_tr VALUES (2, 1), (2, 2);
INSERT INTO ctx_uch_lep_as_uch_tr VALUES (1, 2), (1, 3);
INSERT INTO ctx_provod_as_uch_prov VALUES (2, 1), (2, 2);
INSERT INTO ctx_uch_tr_as_uch_prov VALUES (2, 2), (2, 3);
INSERT INTO ctx_lep_as_uch_tr VALUES (1, 1), (1, 2), (1, 3);
Если же вы захотите еще оперировать и атрибутами объекта, то вы можете добавить любое кол-во различных атрибутов (или наборов атрибутов, если они связаны друг с другом по отношению к объекту, как, например, Имя/Отчество/Фамилия). Вот структура для сохранения «номера трассы», например:
Скрытый текст
CREATE TABLE obj_trassa_attr_num (
id INT(10) UNSIGNED NOT NULL,
value varchar(255) NOT NULL,
PRIMARY KEY (id),
CONSTRAINT obj_trassa_attr_num_to_obj FOREIGN KEY (id) REFERENCES obj_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Номер трассы';
Вам нужна гибкость? Пожалуйста. Но заплатите за нее простотой.
Вот видите, приходится выделять "ведущего" (генератор значения для identity) и от него уже плясать. Можно хоть по одной таблице на атрибут сделать (что, кстати, 6NF и предусматривает), но identity values должны хранится в одном месте, если вы хотите обеспечить их уникальность и консистентность.
Этот подход не является единственно возможным, но является достаточно классическим — как надевать штаны через ноги. Другие варианты, повторюсь, также существуют и некоторые даже имеют своих адептов.
Сложнее всего отвечать на вопросы, имеющие очевидный ответ :) Где у вас ведется учет идентификаторов для новых экземпляров сущностей User — в user_auth, в user_pass, в приложении (в каком экземпляре, если идет балансировка нагрузки)? И что будет, если два процесса одновременно вводят разные данные (auth & pass) по одному пользователю?
Если для вас в подобной конфигурации бред не очевиден, то, скорее всего, мы с вами в наших профессиях ходили разными дорогами.
И что мы имеем в итоге? Две независимые таблицы, каждая из которых имеет свой набор полей, включающий identity-поле, по значению которого и осуществляется сопоставление данных из одной таблицы данным из другой. Никаких внешних связей (foreign keys) друг с другом на уровне структур базы данных. Связывание данных идет в объектной модели на программном уровне.
CREATE TABLE user_auth (
id int(10) UNSIGNED NOT NULL,
username varchar(255) NOT NULL,
...
PRIMARY KEY (id)
);
CREATE TABLE user_pass (
id int(10) UNSIGNED NOT NULL,
firstname varchar(255) NOT NULL,
...
PRIMARY KEY (id)
);
Но ведь именно это я имел в виду, говоря "бред". А вы что имели в виду, говоря "связь 1:1"?
Паспортных с аутентификационными или аутентификационных с паспортными? Кто на кого ссылается? Где находится identity для экземпляра User'а — в паспортных данных или аутентификационных? Могут ли паспортные существовать без идентификационных и наоборот?
Неправильно называть разные конструкции одним и тем же понятием (User), обозначающим весь объект.
Вот и я за то — иметь в программе два разных типа к одному моделируемому объекту на данный момент большинству программистов "религия не позволяет"
А на родительский объект ссылаются по id.
А вот это "религия позволяет". И если у двух разных конструкций (типов) есть совпадение по атрибутам, то ООП-религия позволяет нам ввести промежуточную конструкцию с общими атрибутами и назвать ее "абстрактным типом". И сделать для нее отдельную таблицу и встроить ее в цепочку наследования тоже допустимо.
Ага, так и есть. Вот только иметь в программе два разных типа к одному моделируемому объекту на данный момент большинству программистов "религия не позволяет". Это как иметь в БД две таблицы с различными атрибутами для одной и той же сущности User. Это же бред? Бред. Вот и сливают все атрибуты из различных моделей User'а в одну таблицу и делают одну общую, универсальную модель. Так кошерно.
Программирование — это тоже моделирование. И довольно гибкое. Если уж нельзя в программировании, то о каком "моделировании предметной области" вы сейчас говорите?
Никто не запрещает переименовать "короткую" переменную при "разрастании" однострочника. Это косяк не того, кто однострочник составил, а того, кто его развернул.
Насколько я понял, коллега maxstroy имеет в виду, что один объект реального мира может в приложении моделироваться множеством программных объектов/типов. Причем каждый программный объект описывает со своей точки зрения тот же самый объект, что и остальные программные объекты из этого множества. А приложение должно само выбирать, с какой программной моделью реального объекта ему сейчас наиболее удобно работать. Это как классическая и релятивистская механики — говорим об одном и том же (движение), но с разных точек зрения (субсветовая скорость или обычная).
Коллега michael_vostrikov же говорит о том, что программная модель является лишь приближением к реальной до некоторого уровня детализации и принципиально невозможно сделать универсальную программную модель реального объекта.
Совмещая обе точки зрения в применении к примеру с (не)делимым договором, в приложении может быть два алгоритма — для работы с сущностями, как с атомами, и для работы с ними же, как с композитами. И приложение само, в зависимости от контекста, может выбирать, является ли объект "договор" в текущем контексте атомом (листом дерева) или композитом (узлом дерева).
К сожалению не смогу :( Давно это было, сын уже институт заканчивает. Помню, что меня поразил сам факт наличия в школьном учебнике задачи с неоднозначным решением. Я ему еще тогда авторитетно объяснял, насколько калечит мышление молодого поколения такой вот подход. Каждая задача, мол, имеет одно единственное верное решение и главное — его найти. Каюсь, был неправ.
Но, если навскидку, то путей в лабиринте от входа до выхода может быть более одного. Какой из них правильный?
Сын подсказал еще вариант — тесты на знание Правил Дорожного Движения. Если есть свод правил с противоречащими пунктами (любой кодекс, если покопаться, имеет противоречащие пункты), то на их основании можно сформулировать задачи, имеющие более одного (не)правильного решения — зависит от порядка применения противоречащих пунктов. В народе даже поговорка сложилась "закон — что дышло: куда повернёшь — туда и вышло"
Выйдите с коллегой на один уровень абстракции, ограничьте область обсуждения, и вы увидите, что говорите с ним об одном и том же.
А разве группа не может быть представителем группы? Группа групп, например. Множество множеств. Класс классов. Может. И чем больше мы уходим в абстракт, тем более "может". В пределе "все" — есть "что-то", и каждое "что-то" состоит из других "что-то".
Насколько я понял терминологию, объект — это нечто, существующее в реальности. Модель объекта — это представление реального объекта в рамках моделируемой предметной области. Типы объектов — это некоторая классификация реальных объектов по общим признакам. Объект реального мира может принадлежать к различным типам объектов в зависимости от применяемой классификации. Свойство (признак, атрибут) — некоторая значимая (имеет определенное значение) характеристика объекта. Элемент — часть объекта. Структура (конструкция) — множество различных элементов объекта в совокупности представляющая объект. Объект может быть разделен на элементы различными способами, каждому такому разделению соответствует своя конструкция.
У меня складывается ощущение что вы одновременно говорите за модель предметной области и за мета-модель, в которой "живет" модель предметной области. Если разделить данные на две группы: описание самих объектов (их атрибутов, конструкций и элементов) и описание мета-данных (типов объектов, атрибутов, классов объектов, типов конструкций и типов элементов), то у меня получается примерно вот такая структура:
DROP TABLE IF EXISTS struct_elem, elem_class, elem, struct_class, struct_obj, struct; DROP TABLE IF EXISTS obj_attr, attr_class, obj_class, attr, obj; DROP TABLE IF EXISTS meta_struct_elem, meta_elem, meta_struct; DROP TABLE IF EXISTS meta_classifier_attr, meta_classifier; DROP TABLE IF EXISTS meta_obj_attr, meta_attr, meta_obj; -- -- Мета данные для объектов. -- CREATE TABLE meta_obj ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Реестр типов объектов (деревья, люди, ...)'; CREATE TABLE meta_attr ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Реестр типов атрибутов (высота, имя, ...)'; CREATE TABLE meta_obj_attr ( obj INT(10) UNSIGNED NOT NULL, attr INT(10) UNSIGNED NOT NULL, PRIMARY KEY (obj, attr), CONSTRAINT meta_obj_attr_to_obj FOREIGN KEY (obj) REFERENCES meta_obj (id) ON DELETE CASCADE, CONSTRAINT meta_obj_attr_to_attr FOREIGN KEY (attr) REFERENCES meta_attr (id) ON DELETE CASCADE ) COMMENT = 'Привязка типов атрибутов к типам объектов (высота для деревьев, имена для людей)'; -- -- Мета данные для классификатора объектов. -- CREATE TABLE meta_classifier ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Реестр классов (способов объединения атрибутов объекта для различения экземпляров объектов по значениям атрибутов)'; CREATE TABLE meta_classifier_attr ( class INT(10) UNSIGNED NOT NULL, attr INT(10) UNSIGNED NOT NULL, PRIMARY KEY (class, attr), CONSTRAINT meta_classifier_attr_to_class FOREIGN KEY (class) REFERENCES meta_classifier (id) ON DELETE CASCADE, CONSTRAINT meta_classifier_attr_to_attr FOREIGN KEY (attr) REFERENCES meta_attr (id) ON DELETE CASCADE ) COMMENT = 'Привязка класса к атрибутам, его характеризующим (масса-высота-ширина или долгота-широта)'; -- -- Мета данные для классификатора конструкций. -- CREATE TABLE meta_struct ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Реестр типов конструкций'; CREATE TABLE meta_elem ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Реестр типов элементов конструкций'; CREATE TABLE meta_struct_elem ( struct INT(10) UNSIGNED NOT NULL, elem INT(10) UNSIGNED NOT NULL, PRIMARY KEY (struct, elem), CONSTRAINT meta_struct_elem_to_struct FOREIGN KEY (struct) REFERENCES meta_struct (id) ON DELETE CASCADE, CONSTRAINT meta_struct_elem_to_elem FOREIGN KEY (elem) REFERENCES meta_elem (id) ON DELETE CASCADE ) COMMENT = 'Привязка типов элементов к типам конструкций'; -- -- Предметная область (объекты и их свойства). -- CREATE TABLE obj ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Реестр экземпляров объектов (#1, #2, ...)'; CREATE TABLE obj_class ( obj INT(10) UNSIGNED NOT NULL, class INT(10) UNSIGNED NOT NULL, PRIMARY KEY (obj, class), CONSTRAINT obj_class_to_obj FOREIGN KEY (obj) REFERENCES obj (id) ON DELETE CASCADE, CONSTRAINT obj_class_to_class FOREIGN KEY (class) REFERENCES meta_obj (id) ON DELETE CASCADE ) COMMENT = 'Привязка экземпляров объектов к типам объектов (#1 - дерево, #2 - человек)'; CREATE TABLE attr ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, -- значением атрибута может быть что угодно, включая ссылки на другие объекты; для упрощения - просто некий текст -- каким образом он обрабатывается - решается на программном уровне, для хранилища главное - хранить значение value TEXT NULL, PRIMARY KEY (id) ) COMMENT = 'Реестр значений атрибутов (#1 - тополь, #2 - 3м)'; CREATE TABLE attr_class ( attr INT(10) UNSIGNED NOT NULL, class INT(10) UNSIGNED NOT NULL, PRIMARY KEY (attr, class), CONSTRAINT attr_class_to_attr FOREIGN KEY (attr) REFERENCES attr (id) ON DELETE CASCADE, CONSTRAINT attr_class_to_class FOREIGN KEY (class) REFERENCES meta_attr (id) ON DELETE CASCADE ) COMMENT = 'Привязка значений атрибутов к типам (классам) атрибутов (#1 - порода, #2 - высота)'; CREATE TABLE obj_attr ( obj INT(10) UNSIGNED NOT NULL, attr INT(10) UNSIGNED NOT NULL, PRIMARY KEY (obj, attr), CONSTRAINT obj_attr_to_obj FOREIGN KEY (obj) REFERENCES obj (id) ON DELETE CASCADE, CONSTRAINT obj_attr_to_attr FOREIGN KEY (attr) REFERENCES attr (id) ON DELETE CASCADE ) COMMENT = 'Привязка значений атрибутов к экземплярам объектов (порода объекта #1 - тополь'; -- -- Конструкции и элементы. -- CREATE TABLE struct ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Реестр экземпляров конструкций'; CREATE TABLE struct_obj ( struct INT(10) UNSIGNED NOT NULL, obj INT(10) UNSIGNED NOT NULL, PRIMARY KEY (struct, obj), CONSTRAINT struct_obj_to_struct FOREIGN KEY (struct) REFERENCES struct (id) ON DELETE CASCADE, CONSTRAINT struct_obj_to_obj FOREIGN KEY (obj) REFERENCES obj (id) ON DELETE CASCADE ) COMMENT = 'Привязка экземпляров конструкций к экземплярам объектов'; CREATE TABLE struct_class ( struct INT(10) UNSIGNED NOT NULL, class INT(10) UNSIGNED NOT NULL, PRIMARY KEY (struct, class), CONSTRAINT struct_class_to_struct FOREIGN KEY (struct) REFERENCES struct (id) ON DELETE CASCADE, CONSTRAINT struct_class_to_class FOREIGN KEY (class) REFERENCES meta_struct (id) ON DELETE CASCADE ) COMMENT = 'Привязка экземпляров конструкций к типам конструкций'; CREATE TABLE elem ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, -- элемент конструкции сам является объектом obj INT(10) UNSIGNED NOT NULL, PRIMARY KEY (id), CONSTRAINT elem_to_obj FOREIGN KEY (obj) REFERENCES obj (id) ON DELETE CASCADE ) COMMENT = 'Реестр значений элементов экземпляров конструкций'; CREATE TABLE elem_class ( elem INT(10) UNSIGNED NOT NULL, class INT(10) UNSIGNED NOT NULL, PRIMARY KEY (elem, class), CONSTRAINT elem_class_to_elem FOREIGN KEY (elem) REFERENCES elem (id) ON DELETE CASCADE, CONSTRAINT elem_class_to_class FOREIGN KEY (class) REFERENCES meta_elem (id) ON DELETE CASCADE ) COMMENT = 'Привязка значений элементов к типам элементов'; CREATE TABLE struct_elem ( struct INT(10) UNSIGNED NOT NULL, elem INT(10) UNSIGNED NOT NULL, PRIMARY KEY (struct, elem), CONSTRAINT struct_elem_to_obj FOREIGN KEY (struct) REFERENCES struct (id) ON DELETE CASCADE, CONSTRAINT struct_elem_to_attr FOREIGN KEY (elem) REFERENCES elem (id) ON DELETE CASCADE ) COMMENT = 'Привязка значений элементов к экземплярам конструкций';Сначала заполняются мета-данные, затем описание объектов (хотя объекты можно прописать и без мета-данных к ним). Эта структура позволяет корректно описывать предметную область, но консистентность данных обеспечивается тем, кто их заполняет (программа, человек).
В применении к схеме из самой статьи (с желтыми и зелеными прямоугольниками) что является "структурой", "объектом", "элементом", "типом объектов", "атрибутом"?
Код переформатировался в комменте :( Исправил. Оба фрагмента объединены:
DROP TABLE IF EXISTS obj_trassa_attr_num; DROP TABLE IF EXISTS ctx_lep_as_trassa, ctx_lep_as_uch, ctx_trassa_as_provod, ctx_trassa_as_uch_tr; DROP TABLE IF EXISTS ctx_uch_lep_as_uch_tr, ctx_provod_as_uch_prov, ctx_uch_tr_as_uch_prov, ctx_lep_as_uch_tr; DROP TABLE IF EXISTS obj_lep, obj_trassa, obj_provod, obj_uch_lep, obj_uch_trassa, obj_uch_provod; -- -- Objects (реестры объектов) -- CREATE TABLE obj_lep ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'ЛЭП'; CREATE TABLE obj_trassa ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Трасса'; CREATE TABLE obj_provod ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Провод'; CREATE TABLE obj_uch_lep ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Участок ЛЭП между опорами'; CREATE TABLE obj_uch_trassa ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Участок трассы между опорами'; CREATE TABLE obj_uch_provod ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) ) COMMENT = 'Участок провода между опорами'; -- -- Contexts (контексты/конструкции) -- CREATE TABLE ctx_lep_as_trassa ( lep INT(10) UNSIGNED NOT NULL, trassa INT(10) UNSIGNED NOT NULL, PRIMARY KEY (lep, trassa), CONSTRAINT ctx_lep_as_trassa_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id) ON DELETE CASCADE, CONSTRAINT ctx_lep_as_trassa_to_trassa FOREIGN KEY (lep) REFERENCES obj_trassa (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 1: ЛЭП как трассы'; CREATE TABLE ctx_lep_as_uch ( lep INT(10) UNSIGNED NOT NULL, uch INT(10) UNSIGNED NOT NULL, PRIMARY KEY (lep, uch), CONSTRAINT ctx_lep_as_uch_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id) ON DELETE CASCADE, CONSTRAINT ctx_lep_as_uch_to_uch FOREIGN KEY (uch) REFERENCES obj_uch_lep (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 2: ЛЭП как участки'; CREATE TABLE ctx_trassa_as_provod ( trassa INT(10) UNSIGNED NOT NULL, provod INT(10) UNSIGNED NOT NULL, PRIMARY KEY (trassa, provod), CONSTRAINT ctx_trassa_as_provod_to_trassa FOREIGN KEY (trassa) REFERENCES obj_trassa (id) ON DELETE CASCADE, CONSTRAINT ctx_trassa_as_provod_to_provod FOREIGN KEY (provod) REFERENCES obj_provod (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 3: трасса как провода'; CREATE TABLE ctx_trassa_as_uch_tr ( trassa INT(10) UNSIGNED NOT NULL, uch_tr INT(10) UNSIGNED NOT NULL, PRIMARY KEY (trassa, uch_tr), CONSTRAINT ctx_trassa_as_uch_tr_to_trassa FOREIGN KEY (trassa) REFERENCES obj_trassa (id) ON DELETE CASCADE, CONSTRAINT ctx_trassa_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 4: трасса как участки трассы'; CREATE TABLE ctx_uch_lep_as_uch_tr ( uch_lep INT(10) UNSIGNED NOT NULL, uch_tr INT(10) UNSIGNED NOT NULL, PRIMARY KEY (uch_lep, uch_tr), CONSTRAINT ctx_uch_lep_as_uch_tr_to_uch_lep FOREIGN KEY (uch_lep) REFERENCES obj_uch_lep (id) ON DELETE CASCADE, CONSTRAINT ctx_uch_lep_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 5: участок ЛЭП как участок трассы'; CREATE TABLE ctx_provod_as_uch_prov ( provod INT(10) UNSIGNED NOT NULL, uch_prov INT(10) UNSIGNED NOT NULL, PRIMARY KEY (provod, uch_prov), CONSTRAINT ctx_provod_as_uch_prov_to_provod FOREIGN KEY (provod) REFERENCES obj_provod (id) ON DELETE CASCADE, CONSTRAINT ctx_provod_as_uch_prov_to_uch_prov FOREIGN KEY (uch_prov) REFERENCES obj_uch_provod (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 6: провод как участок провода'; CREATE TABLE ctx_uch_tr_as_uch_prov ( uch_tr INT(10) UNSIGNED NOT NULL, uch_prov INT(10) UNSIGNED NOT NULL, PRIMARY KEY (uch_tr, uch_prov), CONSTRAINT ctx_uch_tr_as_uch_prov_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id) ON DELETE CASCADE, CONSTRAINT ctx_uch_tr_as_uch_prov_to_uch_prov FOREIGN KEY (uch_prov) REFERENCES obj_uch_provod (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 7: участок трассы как участок провода'; CREATE TABLE ctx_lep_as_uch_tr ( lep INT(10) UNSIGNED NOT NULL, uch_tr INT(10) UNSIGNED NOT NULL, PRIMARY KEY (lep, uch_tr), CONSTRAINT ctx_lep_as_uch_tr_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id) ON DELETE CASCADE, CONSTRAINT ctx_lep_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id) ON DELETE CASCADE ) COMMENT = 'Конструкция 8: ЛЭП как участок трассы'; -- -- Данные (объекты) -- INSERT INTO obj_lep VALUES (1); INSERT INTO obj_trassa VALUES (1), (2); INSERT INTO obj_provod VALUES (1), (2); INSERT INTO obj_uch_lep VALUES (1), (2); INSERT INTO obj_uch_trassa VALUES (1), (2), (3); INSERT INTO obj_uch_provod VALUES (1), (2), (3); -- -- Данные (связи в контекстах) -- INSERT INTO ctx_lep_as_trassa VALUES (1, 1), (1, 2); INSERT INTO ctx_lep_as_uch VALUES (1, 1), (1, 2); INSERT INTO ctx_trassa_as_provod VALUES (2, 1), (2, 2); INSERT INTO ctx_trassa_as_uch_tr VALUES (2, 1), (2, 2); INSERT INTO ctx_uch_lep_as_uch_tr VALUES (1, 2), (1, 3); INSERT INTO ctx_provod_as_uch_prov VALUES (2, 1), (2, 2); INSERT INTO ctx_uch_tr_as_uch_prov VALUES (2, 2), (2, 3); INSERT INTO ctx_lep_as_uch_tr VALUES (1, 1), (1, 2), (1, 3); -- -- Атрибуты объектов -- CREATE TABLE obj_trassa_attr_num ( id INT(10) UNSIGNED NOT NULL, value varchar(255) NOT NULL , PRIMARY KEY (id), CONSTRAINT obj_trassa_attr_num_to_obj FOREIGN KEY (id) REFERENCES obj_trassa (id) ON DELETE CASCADE ) COMMENT = 'Номер трассы';Картинку лучше открывать отдельно в новой вкладке, будет более читабельно. Схема данных навеяна Anchor Modeling.
Если вы оперируете объектами, а не их атрибутами, то для их представления вполне достаточно ID объекта и его типа/класса. Классические инструменты вполне позволяют это делать, если не закапываться в дебри. Ваша схема из статьи про ЛЭП/трассы/провода/участки очень хорошо укладывается в типичную RDBMS (MySQL в моем случае). Все, что с префиксом "obj" — это таблицы для желтых элементов вашей схемы, с префиксом "ctx" — для синих:
Вот SQL-код для построения структуры и заполнения ее данными:
DROP TABLE IF EXISTS ctx_uch_lep_as_uch_tr, ctx_provod_as_uch_prov, ctx_uch_tr_as_uch_prov, ctx_lep_as_uch_tr;
DROP TABLE IF EXISTS obj_lep, obj_trassa, obj_provod, obj_uch_lep, obj_uch_trassa, obj_uch_provod;
— — Objects (реестры объектов)
— CREATE TABLE obj_lep (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'ЛЭП';
CREATE TABLE obj_trassa (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Трасса';
CREATE TABLE obj_provod (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Провод';
CREATE TABLE obj_uch_lep (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Участок ЛЭП между опорами';
CREATE TABLE obj_uch_trassa (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Участок трассы между опорами';
CREATE TABLE obj_uch_provod (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
)
COMMENT = 'Участок провода между опорами';
— — Contexts (контексты/конструкции)
— CREATE TABLE ctx_lep_as_trassa (
lep INT(10) UNSIGNED NOT NULL,
trassa INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (lep, trassa),
CONSTRAINT ctx_lep_as_trassa_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_lep_as_trassa_to_trassa FOREIGN KEY (lep) REFERENCES obj_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 1: ЛЭП как трассы';
CREATE TABLE ctx_lep_as_uch (
lep INT(10) UNSIGNED NOT NULL,
uch INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (lep, uch),
CONSTRAINT ctx_lep_as_uch_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_lep_as_uch_to_uch FOREIGN KEY (uch) REFERENCES obj_uch_lep (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 2: ЛЭП как участки';
CREATE TABLE ctx_trassa_as_provod (
trassa INT(10) UNSIGNED NOT NULL,
provod INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (trassa, provod),
CONSTRAINT ctx_trassa_as_provod_to_trassa FOREIGN KEY (trassa) REFERENCES obj_trassa (id)
ON DELETE CASCADE,
CONSTRAINT ctx_trassa_as_provod_to_provod FOREIGN KEY (provod) REFERENCES obj_provod (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 3: трасса как провода';
CREATE TABLE ctx_trassa_as_uch_tr (
trassa INT(10) UNSIGNED NOT NULL,
uch_tr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (trassa, uch_tr),
CONSTRAINT ctx_trassa_as_uch_tr_to_trassa FOREIGN KEY (trassa) REFERENCES obj_trassa (id)
ON DELETE CASCADE,
CONSTRAINT ctx_trassa_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 4: трасса как участки трассы';
CREATE TABLE ctx_uch_lep_as_uch_tr (
uch_lep INT(10) UNSIGNED NOT NULL,
uch_tr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (uch_lep, uch_tr),
CONSTRAINT ctx_uch_lep_as_uch_tr_to_uch_lep FOREIGN KEY (uch_lep) REFERENCES obj_uch_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_uch_lep_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 5: участок ЛЭП как участок трассы';
CREATE TABLE ctx_provod_as_uch_prov (
provod INT(10) UNSIGNED NOT NULL,
uch_prov INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (provod, uch_prov),
CONSTRAINT ctx_provod_as_uch_prov_to_provod FOREIGN KEY (provod) REFERENCES obj_provod (id)
ON DELETE CASCADE,
CONSTRAINT ctx_provod_as_uch_prov_to_uch_prov FOREIGN KEY (uch_prov) REFERENCES obj_uch_provod (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 6: провод как участок провода';
CREATE TABLE ctx_uch_tr_as_uch_prov (
uch_tr INT(10) UNSIGNED NOT NULL,
uch_prov INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (uch_tr, uch_prov),
CONSTRAINT ctx_uch_tr_as_uch_prov_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE,
CONSTRAINT ctx_uch_tr_as_uch_prov_to_uch_prov FOREIGN KEY (uch_prov) REFERENCES obj_uch_provod (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 7: участок трассы как участок провода';
CREATE TABLE ctx_lep_as_uch_tr (
lep INT(10) UNSIGNED NOT NULL,
uch_tr INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (lep, uch_tr),
CONSTRAINT ctx_lep_as_uch_tr_to_lep FOREIGN KEY (lep) REFERENCES obj_lep (id)
ON DELETE CASCADE,
CONSTRAINT ctx_lep_as_uch_tr_to_uch_tr FOREIGN KEY (uch_tr) REFERENCES obj_uch_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Конструкция 8: ЛЭП как участок трассы';
— — Данные (объекты)
— INSERT INTO obj_lep VALUES (1);
INSERT INTO obj_trassa VALUES (1), (2);
INSERT INTO obj_provod VALUES (1), (2);
INSERT INTO obj_uch_lep VALUES (1), (2);
INSERT INTO obj_uch_trassa VALUES (1), (2), (3);
INSERT INTO obj_uch_provod VALUES (1), (2), (3);
— — Данные (связи в контекстах)
— INSERT INTO ctx_lep_as_trassa VALUES (1, 1), (1, 2);
INSERT INTO ctx_lep_as_uch VALUES (1, 1), (1, 2);
INSERT INTO ctx_trassa_as_provod VALUES (2, 1), (2, 2);
INSERT INTO ctx_trassa_as_uch_tr VALUES (2, 1), (2, 2);
INSERT INTO ctx_uch_lep_as_uch_tr VALUES (1, 2), (1, 3);
INSERT INTO ctx_provod_as_uch_prov VALUES (2, 1), (2, 2);
INSERT INTO ctx_uch_tr_as_uch_prov VALUES (2, 2), (2, 3);
INSERT INTO ctx_lep_as_uch_tr VALUES (1, 1), (1, 2), (1, 3);
Если же вы захотите еще оперировать и атрибутами объекта, то вы можете добавить любое кол-во различных атрибутов (или наборов атрибутов, если они связаны друг с другом по отношению к объекту, как, например, Имя/Отчество/Фамилия). Вот структура для сохранения «номера трассы», например:
id INT(10) UNSIGNED NOT NULL,
value varchar(255) NOT NULL,
PRIMARY KEY (id),
CONSTRAINT obj_trassa_attr_num_to_obj FOREIGN KEY (id) REFERENCES obj_trassa (id)
ON DELETE CASCADE
)
COMMENT = 'Номер трассы';
Вам нужна гибкость? Пожалуйста. Но заплатите за нее простотой.
Вот видите, приходится выделять "ведущего" (генератор значения для identity) и от него уже плясать. Можно хоть по одной таблице на атрибут сделать (что, кстати, 6NF и предусматривает), но identity values должны хранится в одном месте, если вы хотите обеспечить их уникальность и консистентность.
Этот подход не является единственно возможным, но является достаточно классическим — как надевать штаны через ноги. Другие варианты, повторюсь, также существуют и некоторые даже имеют своих адептов.
Сложнее всего отвечать на вопросы, имеющие очевидный ответ :) Где у вас ведется учет идентификаторов для новых экземпляров сущностей User — в user_auth, в user_pass, в приложении (в каком экземпляре, если идет балансировка нагрузки)? И что будет, если два процесса одновременно вводят разные данные (auth & pass) по одному пользователю?
Если для вас в подобной конфигурации бред не очевиден, то, скорее всего, мы с вами в наших профессиях ходили разными дорогами.
И что мы имеем в итоге? Две независимые таблицы, каждая из которых имеет свой набор полей, включающий identity-поле, по значению которого и осуществляется сопоставление данных из одной таблицы данным из другой. Никаких внешних связей (foreign keys) друг с другом на уровне структур базы данных. Связывание данных идет в объектной модели на программном уровне.
Но ведь именно это я имел в виду, говоря "бред". А вы что имели в виду, говоря "связь 1:1"?
Паспортных с аутентификационными или аутентификационных с паспортными? Кто на кого ссылается? Где находится identity для экземпляра User'а — в паспортных данных или аутентификационных? Могут ли паспортные существовать без идентификационных и наоборот?
Связь чего с чем? Левых атрибутов User'а с правыми?
Вот и я за то — иметь в программе два разных типа к одному моделируемому объекту на данный момент большинству программистов "религия не позволяет"
А вот это "религия позволяет". И если у двух разных конструкций (типов) есть совпадение по атрибутам, то ООП-религия позволяет нам ввести промежуточную конструкцию с общими атрибутами и назвать ее "абстрактным типом". И сделать для нее отдельную таблицу и встроить ее в цепочку наследования тоже допустимо.
Ага, так и есть. Вот только иметь в программе два разных типа к одному моделируемому объекту на данный момент большинству программистов "религия не позволяет". Это как иметь в БД две таблицы с различными атрибутами для одной и той же сущности User. Это же бред? Бред. Вот и сливают все атрибуты из различных моделей User'а в одну таблицу и делают одну общую, универсальную модель. Так кошерно.
Программирование — это тоже моделирование. И довольно гибкое. Если уж нельзя в программировании, то о каком "моделировании предметной области" вы сейчас говорите?
Никто не запрещает переименовать "короткую" переменную при "разрастании" однострочника. Это косяк не того, кто однострочник составил, а того, кто его развернул.
Насколько я понял, предполагается в приложении иметь различные модели (с различным набором атрибутов) для одного и того же identity.
Насколько я понял, коллега maxstroy имеет в виду, что один объект реального мира может в приложении моделироваться множеством программных объектов/типов. Причем каждый программный объект описывает со своей точки зрения тот же самый объект, что и остальные программные объекты из этого множества. А приложение должно само выбирать, с какой программной моделью реального объекта ему сейчас наиболее удобно работать. Это как классическая и релятивистская механики — говорим об одном и том же (движение), но с разных точек зрения (субсветовая скорость или обычная).
Коллега michael_vostrikov же говорит о том, что программная модель является лишь приближением к реальной до некоторого уровня детализации и принципиально невозможно сделать универсальную программную модель реального объекта.
Совмещая обе точки зрения в применении к примеру с (не)делимым договором, в приложении может быть два алгоритма — для работы с сущностями, как с атомами, и для работы с ними же, как с композитами. И приложение само, в зависимости от контекста, может выбирать, является ли объект "договор" в текущем контексте атомом (листом дерева) или композитом (узлом дерева).
Что такое "холлон"?
К сожалению не смогу :( Давно это было, сын уже институт заканчивает. Помню, что меня поразил сам факт наличия в школьном учебнике задачи с неоднозначным решением. Я ему еще тогда авторитетно объяснял, насколько калечит мышление молодого поколения такой вот подход. Каждая задача, мол, имеет одно единственное верное решение и главное — его найти. Каюсь, был неправ.
Но, если навскидку, то путей в лабиринте от входа до выхода может быть более одного. Какой из них правильный?
Сын подсказал еще вариант — тесты на знание Правил Дорожного Движения. Если есть свод правил с противоречащими пунктами (любой кодекс, если покопаться, имеет противоречащие пункты), то на их основании можно сформулировать задачи, имеющие более одного (не)правильного решения — зависит от порядка применения противоречащих пунктов. В народе даже поговорка сложилась "закон — что дышло: куда повернёшь — туда и вышло"