Как использовать одну общую таблицу для отношений - PullRequest
0 голосов
/ 09 января 2019

Теперь у меня есть таблица, которая «жестко закодирована», чтобы иметь отношение между двумя из одной и той же таблицы с двумя внешними ключами к этой таблице.

До таблицы «Отношения»:

CREATE TABLE IF NOT EXISTS `Item_To_Item` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `item1_id` INT(11) NOT NULL,
  `item2_id` INT(11) NOT NULL,
  `relationship` ENUM('requires', 'mutually_requires', 'required_by', 'relates', 'excludes') NULL DEFAULT NULL,
  `description` VARCHAR(1000) NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_Item1_Id`
    FOREIGN KEY (`item1_id`)
    REFERENCES `Item` (`id`)
  CONSTRAINT `fk_Item2_Id`
    FOREIGN KEY (`item2_id`)
    REFERENCES `Item` (`id`)

Таким образом, до этого имелось двойное отношение много к одному в таблице элементов для заполнения двух внешних ключей.

Теперь необходимо расширить это соотношение, чтобы оно было более общим для таблиц в БД (Enum, Tag, Feature и т. Д.). Таким образом, теперь элементы могут относиться к элементам, элементы могут относиться к тегам, теги могут относиться к тегам и т. Д. Со значением отношения enum.

Что касается общей таблицы, я думаю о том, чтобы добавить таблицу типов, чтобы можно было идентифицировать каждый элемент, тег и т. Д., А затем реструктурировать таблицу отношений так, чтобы она была примерно такой:

CREATE TABLE IF NOT EXISTS `Relationship` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `relater_id` INT(11) NOT NULL,
  `relatee_id` INT(11) NOT NULL,
  `relationship` ENUM('requires', 'mutually_requires', 'required_by', 'relates', 'excludes') NULL DEFAULT NULL,
  `description` VARCHAR(1000) NULL DEFAULT NULL,
  `relater_type_id` INT(11) NULL,
  `relatee_type_id` INT(11) NULL,
  PRIMARY KEY (`id`),
  INDEX `fk_Relatee_Id` (`relatee_id` ASC),
  INDEX `fk_Relater_Id` (`relater_id` ASC),
  CONSTRAINT `fk_Relater_Id`
    FOREIGN KEY (`relater_id`)
  CONSTRAINT `fk_Relatee_Id`
    FOREIGN KEY (`relatee_id`)

Так что теперь вы можете определить, какие типы элементов связаны с помощью type_id и таблицы, и это можно открыть, чтобы любые два идентификатора таблицы могли попасть в столбцы внешнего ключа Relater и Relatee.

Проблема в том, что я не знаю, как иметь такую ​​общность с внешними ключами. Я полагаю, что они могут ссылаться только на одну таблицу, поэтому я не уверен, как делать то, что я хочу, с общей ключевой ссылкой. Кроме того, я вижу проблему с двунаправленными отношениями, когда A взаимно требует B и B, взаимно требует, чтобы A являлись избыточными данными. Я мог бы заблокировать эту избыточность в своем приложении, но мне постоянно приходилось бы проверять наличие двухсторонних A - B || От А. до А. Мне было интересно, как лучше всего выполнить то, что я пытаюсь сделать. Спасибо.

Редактировать: Может быть, использование какого-либо базового типа для моего (элемент, функция, тег) может помочь мне?

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

1 Ответ

0 голосов
/ 09 января 2019

Одним из возможных решений является реализация таблиц object_type и object_index:

CREATE TABLE object_type (
  `object_type_id` int(11) NOT NULL AUTO_INCREMENT,
  `object_type` varchar(30) NOT NULL,
  PRIMARY KEY (`object_type_id`),
  UNIQUE (`object_type`));

CREATE TABLE object_index (
  `object_id` int(11) NOT NULL AUTO_INCREMENT,
  `object_type_id` int(11) NOT NULL,
  PRIMARY KEY (`object_id`),
  UNIQUE (`object_type_id`, `object_id`));

и определите свои отношения только с этой таблицей.

CREATE TABLE IF NOT EXISTS `Relationship` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `relater_id` INT(11) NOT NULL,
  `relatee_id` INT(11) NOT NULL,
  `relationship` ENUM('requires', 'mutually_requires', 'required_by', 'relates', 'excludes') NULL DEFAULT NULL,
  `description` VARCHAR(1000) NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  INDEX `fk_Relatee_Id` (`relatee_id` ASC),
  INDEX `fk_Relater_Id` (`relater_id` ASC),
  CONSTRAINT `fk_Relater_Id`
    FOREIGN KEY (`relater_id`)
    references object_index (`object_id`),
  CONSTRAINT `fk_Relatee_Id`
    FOREIGN KEY (`relatee_id`)
    references object_index (`object_id`));

Затем каждая из ваших таблиц объектов определяется так, что они связаны с object_index в уникальном (object_type_id, object_id) кортеже. В этом примере каждая таблица по умолчанию и проверка ограниченного object_type_id должны быть уникальными:

CREATE TABLE table1 (
  `object_id` int(11) NOT NULL,
  `object_type_id` int(11) NOT NULL DEFAULT 1 CHECK (object_type = 1),
  `col1` varchar(4),
  PRIMARY KEY (`object_id`),
  CONSTRAINT fk_t1_ob_idx
    FOREIGN KEY (`object_type_id`, `object_id`)
    REFERENCES object_index (`object_type_id`, `object_id`));

В MySQL 5.6 и выше вы можете определить виртуальный / вычисляемый столбец в каждой таблице, чтобы он совпадал с object_type_id из object_index вместо сохраненного физического столбца.

В MySQL 8.0 и более поздних версиях вы можете определить индекс на основе функций для каждой таблицы, который включает дискриминатор object_type_id в качестве выражения, а не в качестве физического или виртуального столбца в таблице.

...