2010-10-22 41 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 

现在,这是好的,但我的工作需要,系统将变得更加富有活力,在新模块可以很容易地引入和集成。所以,现在如果我添加一个媒体表我需要拆分变更记录条和媒体之间具有

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”更好? – 2010-10-22 18:14:33

回答

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

谢谢您的详细回复。我非常喜欢这种设计,并将在我的进一步研究中考虑它。 – Dan 2010-10-22 18:43:16

+0

关闭问题的循环,谢谢汤姆H.,你的方法似乎很好地满足我的设计。希望很少有变化需要在这条路上完成。 – Dan 2010-10-29 17:48:12

2

在我看来,你问的指南,导致你扭转,布满荆棘的道路。

我不知道为什么你需要每次你得到一个新的“模块”添加(我不明白一个模块是什么)新表中提供的模块都可以使用相同的列布局描述。您可以添加一个Modules表,然后在Articles表中包含一个ModuleId列。

此外,文章可以有多个作者,所以,如果你这样做,你需要一个ArticleAuthors表。在一些圈子里,作者对文章的顺序是重要的。这是他们贡献的重要性或其在该领域的重要性的排名。如果是这样的话,你需要有一个“序号”栏来反映作者的位置。

+0

感谢您的快速回复Tim;模块表示我正在处理的CMS的子系统。文章的多位作者可以由原作者User和后续作者编辑来表示。用户是按级别排列的(为了简单起见,我没有在示例模型中包含许多不相关的字段)我一直希望找到某种“表格ID”解决方案,它独立于模型本身... – Dan 2010-10-22 17:41:50

+1

为了进一步扩展,我确实有一个Modules表,用于注册和取消注册模块(以及保存配置参数等),但是一个Module可能有多个表格,例如具有Track和Album的Discography。 Track和Album都需要单独的ChangeHistory表(或公共中间表中的引用),因此单个module_id不足以引用Track和Album。 – Dan 2010-10-22 18:01:43

2

我想你可能是最好关闭与单个变更记录表,看起来像:(如文章,媒体等)

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

,然后用changedItemType_id弄清楚什么改变基于itemType表。通过这种方式,您只能为所有内容更改历史记录提供一张表格,添加/删除模块时无需添加/删除表格,只需更新itemType表格即可。当然,这意味着必须小心地删除一个模块 - 您可以留下引用该模块类型(但很乱)的记录或删除与模块相关的所有历史记录。


现在你提到一个模块可以有其它的表,所以也许那些需要用一个子模块ID,在ItemChangeHistory还引用跟踪?

0

为什么不

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

@Majid: 我明白那是可能是最合理的解决办法,但我希望能找到一些更直观的东西能利用现有数据库的参数优势;例如难以捉摸的(并且显然不存在的)表格ID(我的意思是某种内部引用,引擎InnoDB在我的例子中用来描述表格)

@frustrated: 我想我是去那样的事情。我将继续调查可能性。

相关问题