Таблицы базы данных, одна таблица ссылается на несколько несвязанных таблиц - PullRequest
5 голосов
/ 22 октября 2010

Этот вопрос несколько раз поднимался на разных форумах в моем поиске, но ни один из них не дал краткого решения.

Если у меня есть следующие таблицы:

User
+- id
+- username
+- password

Article
+- id
+- title
+- content

и я хочу присоединиться к ним, чтобы определить, кто какие статьи создал, я мог бы просто добавить столбец user_id в Статья , чтобы использовать его в качестве ссылки. Кроме того, я добавляю промежуточную таблицу, чтобы показать, кто / когда / что, например:

User
+- ...

Article
+- ...

ChangeHistory
+- id
+- article_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime

Теперь это нормально, но система, над которой я работаю, должна быть гораздо более динамичной, так как новые модули могут быть легко внедрены и интегрированы. Теперь, если я добавлю таблицу Media , мне нужно разделить ChangeHistory между Article и Media , имеющими:

User
+- ...

Article
+- ...

Media
+- id
+- title
+- path

ArticleChangeHistory
+- id
+- article_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime

MediaChangeHistory
+- id
+- media_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime

Это может быстро выйти из-под контроля с появлением множества модулей. Каждый модуль должен нести ответственность за создание и управление своей собственной ChangeHistory таблицей.

TL; DR: Какие методы я могу изучить, чтобы создать промежуточную таблицу, которая может получать ссылки на несколько других не связанных таблиц? Я мог бы добавить поле * record_type *, содержащее имя таблицы, к которой принадлежит запись, но это ужасно. Мне нужно что-то вроде " идентификатор таблицы ", чтобы ссылаться на таблицу, из которой он идет. Таким образом, когда / если модули добавляются или удаляются, модель не разваливается.

Есть идеи? Большое спасибо заранее.

Ответы [ 5 ]

4 голосов
/ 22 октября 2010

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

В каждом случае, когда я видел шаблон (или анти-шаблон?) Попытки сделать общий стол "все делает", он упал лицом вниз. СУРБД лучше всего работают с четко определенными проблемными областями. Если у модуля есть необходимость вести историю, тогда модуль должен добавить таблицу истории, чтобы идти вместе с самой таблицей. Это также имеет огромное преимущество в том, что в будущем вы, вероятно, захотите хранить разные типы информации в истории в зависимости от таблицы или модуля, для которого хранится история. Если у вас есть общая таблица истории, которая становится намного сложнее.

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

CREATE TABLE Audited_Items
(
    id    INT    NOT NULL    IDENTITY,
    CONSTRAINT PK_Audited_Items PRIMARY KEY CLUSTERED (id)
)
CREATE TABLE Articles
(
    id    INT            NOT NULL,
    [Article specific columns]
    CONSTRAINT PK_Articles PRIMARY KEY CLUSTERED (id),
    CONSTRAINT FK_Articles_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id)
)
CREATE TABLE Media
(
    id    INT            NOT NULL,
    [Media specific columns]
    CONSTRAINT PK_Media PRIMARY KEY CLUSTERED (id),
    CONSTRAINT FK_Media_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id)
)
CREATE TABLE Audit_Trail
(
    audited_item_id    INT         NOT NULL,
    audit_datetime     DATETIME    NOT NULL,
    user_id            INT         NOT NULL,
    [audit columns]
    CONSTRAINT PK_Audit_Trail PRIMARY KEY CLUSTERED (audited_item_id, audit_datetime),
    CONSTRAINT FK_Audit_Trail_Audited_Items FOREIGN KEY (audited_item_id) REFERENCES Audited_Items (id)
)
2 голосов
/ 22 октября 2010

Я думаю, что вам лучше всего использовать одну таблицу ChangeHistory, которая выглядит примерно так:

ItemChangeHistory
+- id
+- changedItem_id
+- user_id
+- changedItemType_id
+- type [enum(insert, update, delete)]
+- datetime

, а затем используйте changedItemType_id, чтобы выяснить, что было изменено (например, статья, медиа и т. Д.) На основе таблицы itemType. Таким образом, у вас есть только одна таблица для всех историй изменений содержимого, и вам не нужно добавлять / удалять таблицы при добавлении / удалении модулей, вы просто обновляете таблицу itemType. Конечно, это означает, что удаление модуля должно выполняться осторожно - вы можете оставить ItemChangeHistory записи, которые ссылаются на тип этого модуля (но это не так), или удалить всю историю, связанную с модулем.


Теперь вы упоминаете, что у модуля могут быть другие таблицы, поэтому, возможно, их нужно отслеживать с помощью идентификатора субмодуля, также упоминаемого в ItemChangeHistory?

2 голосов
/ 22 октября 2010

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

Я не знаю, зачем вам нужно добавлять новую таблицу каждый раз, когда вы получаете новый «модуль» (мне непонятно, что это за модуль), при условии, что все модули могут быть описаны с одинаковым расположением столбцов. Вы можете добавить таблицу модулей и затем включить столбец ModuleId в таблицу статей.

Кроме того, статьи могут иметь более одного автора, так что если у вас есть, вам понадобится таблица ArticleAuthors. И в некоторых кругах порядок авторов по статье важен. Это рейтинг важности их вклада или их важности в этой области. Если это так, вам нужен столбец с порядковым номером, отражающий позицию автора.

0 голосов
/ 22 октября 2010

@ Маджид: Я понимаю, что это, вероятно, самое разумное решение, но я надеялся найти что-то более интуитивное, что-то, что могло бы потенциально использовать преимущества существующих параметров БД;такие как неуловимый (и явно несуществующий) идентификатор таблицы (под которой я подразумеваю какую-то внутреннюю ссылку, которую движок, InnoDB в моем случае, использует для описания таблиц)Я собираюсь пойти с чем-то в этом роде.Я собираюсь продолжать исследовать возможности.

0 голосов
/ 22 октября 2010

Почему бы не

ChangeHistory
+- id
+- content_id
+- content_type
+- user_id
+- action [enum(added, updated, deleted)]
+- datetime
...