我考虑创建一个具有唯一ID的表,所有实体都引用该ID,并在标记表和“唯一ID”表之间建立n:m关系。这样,“唯一ID”表和标记表之间只有一个交叉表。
以防有些人认为已经提出了这个问题。我已经阅读了Database Design for Tagging,那里提到了三表设计。
我认为使用一个表格来记录所有标签分配并没有什么问题(而不是为每个可标记实体创建多个表格)。
然而,在你的设计中,有一个重要的细节让我感到困惑:如果你打算采用类似以下的方式
- - - - - - - - - -
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
实例,因此也不需要与实体相关的所有代码都了解标签。但是,如果在系统中标记将变得非常普遍,并且您确定不需要为实体使用任何其他“公共祖先”(即除Taggable
之外的实体),那么您可能可以不使用实体的“内在”ID。Taggable
。但是:Taggable
将是实体的唯一“公共祖先”,那么使用Taggable_ID
FK作为实体的PK就可以了。但是,例如,如果某些实体恰好也是“可观察的”(考虑通知、通知计划等),或者“可做任何事情”:-),我们是否可以通过将任何实体硬绑定到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)
CREATE TABLE Recipes (
recipe_id INT NOT NULL PRIMARY KEY, -- not auto-generated
FOREIGN KEY (recipe_id) REFERENCES Taggables(id)
);
Recipes
和Ingredients
中的行指向Taggables
中同一行的情况。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冲突的潜力。
我认为你走在了正确的道路上。你描述得非常好,你有几个不同的实体。你可以创建一个名为“entities”的表,其中包含所有共同的属性(如果有的话)。例如:
实体
成分
食谱发布者
现在你可以有一个标记实体的表。
这个怎么样?
类型(主键:类型,集合ID[,类型描述])
属性(主键:(集合ID,外键:类型),值)
附注:加粗/斜体真的很糟糕
正常情况下,为食谱、配料等制作表格。
然后您的标签表格应该如下所示:Id、Type、Tag。
我建议在代码中使用枚举来区分不同的“类型”(实体)。
我手头也有一个类似的“问题”。我正在开发一个小型产品数据库,其中涉及标记并为标记赋值(例如标记名称:颜色,值:绿色)。
主要的两个表是物品(I)和文章(A)。物品是实际的物品,而文章则是从物品中派生出来的。文章是可以在网站上显示的内容,而物品则是存储在仓库中的物品。 这种关系的一个小例子可能是汽车零件。具有已知尺寸和其他数据的散热器实际上可以适合许多不同的型号和制造商,这就是用于表示散热器的物品与指示散热器适合哪些车型的多个文章相关联的原因。 另一方面,我们可能会为一个型号提供两种不同的散热器,一种是全新的工厂版本,另一种是重新制造的版本。在这种情况下,存在两个与同一篇文章相关联的物品。
因此,我和A之间存在N:M的关系。
物品和文章都有一些属性。例如,散热器可能具有诸如状态、材料、重量、高度、宽度和厚度等数据。
文章还有一些基本信息,例如制造商、型号、年份、发动机等,但也可能需要一些特殊数据,例如底盘型号、变速器类型或者是在同一型号上使用的两种不同配件类型之类的东西。
因为两个物品可以链接到一个文章,这意味着我不能只标记文章。用两个条件值标记文章是愚蠢的,另一方面,将一个物品标记为多个模型、制造商或某些特殊要求的实例也不是一个好主意。有两种属性类型,第一种表示某些东西的样子,第二种表示它适合什么。
标签不一定要有值,它们可以只作为分配给实体的传统标签。
散热器只是一个简单产品的例子。我们也可以在数据库中放置一些计算机零件或服装。这意味着我需要能够在两个不同的实体I和A上放置不同的“标签”。
我需要能够在网店中实现文章搜索功能。假设我正在使用基于树的导航,其中有一个名为“二手日产散热器”的类别。 搜索将涉及搜索文章和物品,文章具有标记Model:Nissan,物品具有标记Condition:Used。 当然,当用户查看文章时,他确实会看到与文章相关联的所有物品。
我正在考虑的解决方案之一是三角形数据库设计,其中有一个名为tags的通用表格,用于所有属性和标记。
我们有项目(I),文章(A)和标记(T)表格 它们通过N:M关系连接: I2A将项目连接到文章。 T2I将标记连接到物品,并可能存储标记或属性的值。 T2A将标记连接到文章,并可能为标记存储值。
在纸上,这个用于解决此问题的6个表格设计看起来非常不错,但我正在努力形成一个体面的查询,以选择匹配一组不同标记及其值的文章,例如:Condition=Remanufactured,Make=Nissan
我想做的是像www.summitracing.com一样。在“Shop”下面左侧选择“部门”,然后选择任何类别,您将看到他们如何成功地为项目添加属性。他们对大多数应用程序都有引擎大小,但是在寻找轮毂时,他们还有一个宽度属性。