Гибкая структура БД для объекта с несколькими связями и наследованием - PullRequest
0 голосов
/ 13 марта 2019

Я разрабатываю структуру базы данных с некоторыми конкретными правилами и пытаюсь определить правильную модель данных, в основном такую, которая соответствует этим правилам.

Есть 3 объекта:

  1. Группа (поля: subgroups, items ...)
  2. Подгруппа (поля: group, items ...)
  3. Элемент (поля: enabled, description ...)

Эти сущности имеют отношения:

  • A SubGroup принадлежит Group (a Group владеет несколькими SubGroup)
  • Item может принадлежать Group или SubGroup (только по одному за раз)

И существуют специальные правила:

  • Item, принадлежащий Group, наследуется всем связанным SubGroup
  • Item, который наследуется SubGroup от его Group, может быть переопределен (я называю это наследованием, потому что это то, что он чувствует, то, что наследуется родителем и может быть переопределено или использовано как есть)
    • Основной вариант использования переопределения, который у меня есть, связан с полем enabled, потому что в некоторых случаях мы можем захотеть отключить элемент, поступающий по наследству
  • Не дублировать содержимое (в частности, элементы) в БД (наследование должно выполняться при запросе модели БД на уровне приложения)

Этот пример прост, но реальность немного сложнее, может быть больше уровней «SubGroup», например «SubSubGroup», поэтому структура должна обрабатывать их также изящно


Попытка 1

Сначала я представлял себе традиционные отношения:

enter image description here

И это бы хорошо работало, если бы не эти "особые правила". Потому что с этой структурой невозможно переопределить унаследованный Item.

Поэтому я предпринял вторую попытку также справиться с этим.


Попытка 2

Я предпринял еще одну попытку разработки, используя своего рода "прокси" таблицу, в основном таблицу отношений nn с именем ItemOverride (название ужасное, но я не нашел ничего лучшего) в дополнение к существующие сущности (Group, SubGroup и Item)

Сущность ItemOverride содержит следующие поля:

  • ItemId
  • EntityType (Group или SubGroup)
  • EntityId (идентификатор, связанный с выбранным EntityType)

Сущность ItemOverride расширяет сущность Item, так что она содержит те же поля, позволяя переопределить любое поле.

Пример содержимого в таблице ItemsOverride:

+--------+------------+----------+-----------------+---------------------+
| ItemId | EntityType | EntityId | Enabled         |    OverriddenHeight |
+--------+------------+----------+-----------------+---------------------+
|     1  | group      |        1 | true            | null                |
|     2  | group      |        2 | true            | 20                  |
|     3  | subgroup   |        1 | false           |                     |
+--------+------------+----------+-----------------+---------------------+

Кажется, этот дизайн обеспечивает правильную структуру, я добавил OverriddenWidth и OverriddenHeight, чтобы проиллюстрировать переопределенные поля. Смысл в том, чтобы хранить только то, что было переопределено, и оставлять другие значения пустыми, чтобы для получения этих значений использовалась действительная сущность Item.

Но я чувствую, что все становится намного сложнее, чем нужно, и мне интересно, нет ли лучшего способа справиться с этим.

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

  • Если объект ItemOverride наследует Item, то поля, которые не допускают "ноль", должны быть установлены в таблице ItemOverride, что приведет к пустой трате пространства, дублированному содержимому и другим проблемы, потому что будет сложнее увидеть, что действительно переопределено из того, что унаследовано
  • Если между ItemOverride и Item нет наследования, то модель ItemOverride будет "бесполезно" дублировать большинство своих полей, и добавление / обновление / удаление полей придется выполнять в двух таблицах вместо одной

Итак, я не знаю, достаточно ли хорош этот дизайн или его можно улучшить / упростить. Мне было бы интересно погрузиться в подобный проект с такими потребностями наследования / переопределения, если вы знаете что-либо.


Резюме:

Моя вторая попытка, кажется, соответствует моим потребностям, и это то, что я бы использовал, если бы мне пришлось начать немедленно, потому что я не вижу, как ее улучшить.

В этой схеме нет избыточности данных, но все еще неясно, как обрабатывать переопределение данных, когда SubGroup наследует Group Item.Если переопределение ограничено полем required, то это довольно просто, но если его много, то его становится немного сложнее поддерживать.Использование наследования модель / таблица также может усложнить ситуацию, поскольку мы не хотим хранить значения, не являющиеся переопределенными, и поэтому хотим разрешить null для всех полей в таблице ItemOverride (что может быть невозможно, если мы применяем не-nullable правила в сущности Item, потому что они также будут применяться к ItemOverride)

Вопрос: есть ли способ использовать наследование и переопределение, не дублируя ни конфигурацию столбцов, нисами данные?


Для записи я использую Django.Его мощный внутренний ORM изящно работает с ContentTypes и DynamicRelationship, они позволяют ссылаться на динамический объект, используя поля модели.(то, на что я ссылаюсь как EntityType/EntityId), и это одна из причин, почему дизайн 2-й попытки спроектирован таким образом (проще полагаться на то, что обеспечивает моя инфраструктура).Но я открыт для совершенно разных возможностей / выборов.

...