Обновить
8K+
53
Alex Gusev@flancer

Я кодирую, потому что я кодирую…

9,2
Рейтинг
99
Подписчики
Отправить сообщение

Выйдите с коллегой на один уровень абстракции, ограничьте область обсуждения, и вы увидите, что говорите с ним об одном и том же.

А разве группа не может быть представителем группы? Группа групп, например. Множество множеств. Класс классов. Может. И чем больше мы уходим в абстракт, тем более "может". В пределе "все" — есть "что-то", и каждое "что-то" состоит из других "что-то".

Насколько я понял терминологию, объект — это нечто, существующее в реальности. Модель объекта — это представление реального объекта в рамках моделируемой предметной области. Типы объектов — это некоторая классификация реальных объектов по общим признакам. Объект реального мира может принадлежать к различным типам объектов в зависимости от применяемой классификации. Свойство (признак, атрибут) — некоторая значимая (имеет определенное значение) характеристика объекта. Элемент — часть объекта. Структура (конструкция) — множество различных элементов объекта в совокупности представляющая объект. Объект может быть разделен на элементы различными способами, каждому такому разделению соответствует своя конструкция.


У меня складывается ощущение что вы одновременно говорите за модель предметной области и за мета-модель, в которой "живет" модель предметной области. Если разделить данные на две группы: описание самих объектов (их атрибутов, конструкций и элементов) и описание мета-данных (типов объектов, атрибутов, классов объектов, типов конструкций и типов элементов), то у меня получается примерно вот такая структура:


Скрытый текст
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" — для синих:


image


Вот 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'а с правыми?

Неправильно называть разные конструкции одним и тем же понятием (User), обозначающим весь объект.

Вот и я за то — иметь в программе два разных типа к одному моделируемому объекту на данный момент большинству программистов "религия не позволяет"


А на родительский объект ссылаются по id.

А вот это "религия позволяет". И если у двух разных конструкций (типов) есть совпадение по атрибутам, то ООП-религия позволяет нам ввести промежуточную конструкцию с общими атрибутами и назвать ее "абстрактным типом". И сделать для нее отдельную таблицу и встроить ее в цепочку наследования тоже допустимо.

Ага, так и есть. Вот только иметь в программе два разных типа к одному моделируемому объекту на данный момент большинству программистов "религия не позволяет". Это как иметь в БД две таблицы с различными атрибутами для одной и той же сущности User. Это же бред? Бред. Вот и сливают все атрибуты из различных моделей User'а в одну таблицу и делают одну общую, универсальную модель. Так кошерно.

Программирование — это тоже моделирование. И довольно гибкое. Если уж нельзя в программировании, то о каком "моделировании предметной области" вы сейчас говорите?

Никто не запрещает переименовать "короткую" переменную при "разрастании" однострочника. Это косяк не того, кто однострочник составил, а того, кто его развернул.

Не меняется то, что называется английским словом identity. И именно это мы связываем с объектом в целом.

Насколько я понял, предполагается в приложении иметь различные модели (с различным набором атрибутов) для одного и того же identity.

Насколько я понял, коллега maxstroy имеет в виду, что один объект реального мира может в приложении моделироваться множеством программных объектов/типов. Причем каждый программный объект описывает со своей точки зрения тот же самый объект, что и остальные программные объекты из этого множества. А приложение должно само выбирать, с какой программной моделью реального объекта ему сейчас наиболее удобно работать. Это как классическая и релятивистская механики — говорим об одном и том же (движение), но с разных точек зрения (субсветовая скорость или обычная).


Коллега michael_vostrikov же говорит о том, что программная модель является лишь приближением к реальной до некоторого уровня детализации и принципиально невозможно сделать универсальную программную модель реального объекта.


Совмещая обе точки зрения в применении к примеру с (не)делимым договором, в приложении может быть два алгоритма — для работы с сущностями, как с атомами, и для работы с ними же, как с композитами. И приложение само, в зависимости от контекста, может выбирать, является ли объект "договор" в текущем контексте атомом (листом дерева) или композитом (узлом дерева).

К сожалению не смогу :( Давно это было, сын уже институт заканчивает. Помню, что меня поразил сам факт наличия в школьном учебнике задачи с неоднозначным решением. Я ему еще тогда авторитетно объяснял, насколько калечит мышление молодого поколения такой вот подход. Каждая задача, мол, имеет одно единственное верное решение и главное — его найти. Каюсь, был неправ.


Но, если навскидку, то путей в лабиринте от входа до выхода может быть более одного. Какой из них правильный?


Сын подсказал еще вариант — тесты на знание Правил Дорожного Движения. Если есть свод правил с противоречащими пунктами (любой кодекс, если покопаться, имеет противоречащие пункты), то на их основании можно сформулировать задачи, имеющие более одного (не)правильного решения — зависит от порядка применения противоречащих пунктов. В народе даже поговорка сложилась "закон — что дышло: куда повернёшь — туда и вышло"

Информация

В рейтинге
845-й
Откуда
Рига, Латвия, Латвия
Дата рождения
Зарегистрирован
Активность

Специализация

Фулстек разработчик
Ведущий
От 3 000 €
JavaScript
HTML
CSS
Node.js
Vue.js
Веб-разработка
Progressive Web Apps
PostgreSQL
MySQL
GitHub