2010-10-22 2 views
5

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

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

User 
+- id 
+- username 
+- password 

Article 
+- id 
+- title 
+- content 

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

User 
+- ... 

Article 
+- ... 

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

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

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 *, содержащее имя таблицы, к которой принадлежит запись, но это уродливо. Мне нужно что-то вроде таблицы «ID», чтобы ссылаться на таблицу, из которой она идет. Таким образом, когда/если модули добавляются или удаляются, модель не разваливается.

Любые идеи? Большое спасибо заранее.

+0

Есть ли причина, по которой вы считаете, что «ID таблицы» лучше, чем «record_type»? –

ответ

4

По моему опыту, когда разработчики пытаются сделать свою систему действительно «динамический», они на самом деле пытаются кодировать проблемы, которые они не думали до сих пор. Это обычно плохой путь. Действительно ли это такая дополнительная работа для модуля, который включает две таблицы вместо одной?

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

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

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) 
) 
+0

Благодарим вас за подробный ответ Tom. Мне очень нравится этот дизайн, и я буду рассматривать его в своих дальнейших исследованиях. – Dan

+0

Закрытие цикла на вопрос, спасибо Том Х., ваш метод, похоже, удовлетворяет моему дизайну достаточно хорошо. Надеемся, что в будущем нам нужно будет немного изменить. – Dan

2

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

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

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

+0

Спасибо за ваш быстрый ответ Тим; Модули представляют собой подсистемы CMS, над которыми я работаю. Несколько авторов статьи могут быть представлены оригинальным автором User и последующими авторскими редакциями. Пользователи оцениваются по уровню (я просто не использовал много ненужных полей в своих примерах для упрощения). Я надеялся найти какое-то решение «table-ID», которое не зависит от самой модели ... – Dan

+1

Чтобы развернуть немного больше, у меня есть таблица модулей, для регистрации и отмена регистрации модулей (и сохранения параметров конфигурации и т. Д.), Но модуль может иметь несколько таблиц, таких как Дискография с дорожкой и альбомом. Для обоих треков и альбомов нужны отдельные таблицы ChangeHistory (или ссылки в общей промежуточной таблице), и поэтому одного модуля_id не хватит для ссылки на трек и альбом. – Dan

2

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

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

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


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

0

Почему не

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

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

@frustrated: Я полагаю, что я собираюсь пойти с чем-то подобным. Я продолжу расследование.