Database design 用于标记多种类型实体的数据库设计
我目前正在设计一个用于存储食谱的数据库模式。在这个数据库中,我希望能够标记不同类型的实体(配料、配方发布者、配方等)。所以一个标记有多个n:m关系。如果我使用“三表设计”,这将为我拥有的每种实体类型(配方、成分、发行人)生成表(交叉表)。换句话说,每次我引入一个实体时,我必须为它添加一个交叉表 我正在考虑创建一个表,该表具有所有实体都引用的唯一id,并且在标记表和“唯一id”表之间有一个n:m关系。这样,“唯一id”表和标记表之间只有一个交叉表Database design 用于标记多种类型实体的数据库设计,database-design,tagging,Database Design,Tagging,我目前正在设计一个用于存储食谱的数据库模式。在这个数据库中,我希望能够标记不同类型的实体(配料、配方发布者、配方等)。所以一个标记有多个n:m关系。如果我使用“三表设计”,这将为我拥有的每种实体类型(配方、成分、发行人)生成表(交叉表)。换句话说,每次我引入一个实体时,我必须为它添加一个交叉表 我正在考虑创建一个表,该表具有所有实体都引用的唯一id,并且在标记表和“唯一id”表之间有一个n:m关系。这样,“唯一id”表和标记表之间只有一个交叉表 以防有人认为这个问题已经被问到了。我已经读过了。这
以防有人认为这个问题已经被问到了。我已经读过了。这里提到了三张桌子的设计。我认为你的思路是对的。你描述得很好,你有几个不同的实体。您可以创建一个名为entities的表,其中包含所有公共属性(如果有)。比如说 实体
- 实体ID
- 名字
- 实体ID
- 数量
- 实体ID
- 其他信息
注:粗体/斜体字真的很吸引人将表格制作成普通的食谱、配料等 那么您的标记表应该如下所示:Id、Type、tag
我建议在代码中使用枚举来区分不同的“类型”(实体)。我不认为所有标记分配都使用一个表有什么错(与多个表相反,每个标记实体一个表) 然而,您的设计中的一个重要细节对我来说仍然模棱两可:如果您打算按照这些思路进行设计
- - - - - - - - - -
Tag
ID // PK
Name
...
- - - - - - - - - -
Taggable
ID // PK
...
- - - - - - - - - -
TagAssignment
Tag_ID // FK -> Tag.ID
Taggable_ID // FK -> Taggable.ID
...
- - - - - - - - - -
EntityOne
Taggable_ID // FK -> Taggable.ID
...
- - - - - - - - - -
EntityTwo
Taggable_ID // FK -> Taggable.ID
...
那么您的实体类将拥有自己的主键,还是将使用EntityOne.TaggableID
和EntityTwo.TaggableID
作为EntityOne
和EntityTwo
的事实主键
在大多数情况下,我会谨慎行事,让实体拥有自己的ID:
- - - - - - - - - -
EntityOne
ID // PK
Taggable_ID // FK -> Taggable.ID (Nullable)
...
- - - - - - - - - -
EntityTwo
ID // PK
Taggable_ID // FK -> Taggable.ID (Nullable)
...
这并不要求每个实体都有一个对应的Taggable
实例,因此也不要求与实体相关的每段代码都知道标记。但是,如果标记在系统中真的无处不在,并且如果您确信实体不需要任何其他“公共祖先”(即,除了可标记的
),那么您可能不需要实体的“固有”ID
NB:我从来没有尝试过实现这样的事情,所以我所有的建议都是纯理论性的。所以,如果我没有看到一些明显的缺陷,请不要向我开枪。:-)
针对比尔·卡温的评论: 您是对的:上述设计不会阻止多个实体引用相同的
Taggable
。但是:
Taggable
将是实体的唯一“共同祖先”,那么可以使用Taggable_ID
FKs作为实体的PKs。但是,例如,如果一些恰好是“可标记”的实体也必须是“可监视的”(考虑通知、通知时间表等)或“任何可监视的”:-?我们可以通过将任何实体绑定到Taggable
来切断所有这些“能力”吗- - - - - - - - - -
Taggable
ID // PK
Type
...
- - - - - - - -
Constraint: (ID, Type) is unique
- - - - - - - - - -
EntityOne
ID
Taggable_ID
Taggable_Type // Constraint: always = 'EntityOne'
...
- - - - - - - -
FK: (Taggable_ID, Taggable_Type) -> (Taggable.ID, Taggable.Type)
当然,所有这些都比把实体绑定到标记上要复杂得多。但我只是想讨论一下,以我的拙见,除了原始问题提供的狭窄图片之外,还应该考虑什么。我想说,这取决于您希望如何使用标签 我可以想象,如果一次只搜索一种类型的实体,您可以为要标记的每种实体类型创建一个额外的交集表。换句话说,说“给我看标有‘yummy’标签的配料”是正常的,但不清楚说“给我看标有‘yummy’标签的配料和配方发布者”是什么意思。在这种情况下,每个实体都有一个单独的交叉表是可以的 但是如果您确实需要搜索具有给定标记的所有类型的所有实体,那么使用单个“ID”表就更容易了。使所有实体表都指向它,其中包含一列定义为主键和外键:
CREATE TABLE Recipes (
recipe_id INT NOT NULL PRIMARY KEY, -- not auto-generated
FOREIGN KEY (recipe_id) REFERENCES Taggables(id)
);
此计划的唯一缺点是,您无法阻止配方
和配料
中的一行指向标记栏中的同一行
INSERT INTO Taggables (id) VALUES (327);
INSERT INTO Recipes (recipe_id, name) VALUES (327, 'Hollandaise sauce');
INSERT INTO Ingredients (ingr_id, name) VALUES (327, 'eggs');
你想让每一个与鸡蛋相关的标签也适用于荷兰酱吗
我只是指出单表设计的这一方面。考虑到其他需求,它可能仍然是建模标记的最佳方式。但您应该注意从属表中id的冲突可能性。我也有类似的“问题”。我正在开发一个小的产品数据库,它涉及到标记和给标记一个值(例如标记名:颜色,值:绿色)
两个主要表格分别为项目(I)和条款(A)。物品是实际的实物物品,物品是从物品衍生出来的。文章是可以在网站上显示的东西,而项目是