Database design 用于标记多种类型实体的数据库设计

Database design 用于标记多种类型实体的数据库设计,database-design,tagging,Database Design,Tagging,我目前正在设计一个用于存储食谱的数据库模式。在这个数据库中,我希望能够标记不同类型的实体(配料、配方发布者、配方等)。所以一个标记有多个n:m关系。如果我使用“三表设计”,这将为我拥有的每种实体类型(配方、成分、发行人)生成表(交叉表)。换句话说,每次我引入一个实体时,我必须为它添加一个交叉表 我正在考虑创建一个表,该表具有所有实体都引用的唯一id,并且在标记表和“唯一id”表之间有一个n:m关系。这样,“唯一id”表和标记表之间只有一个交叉表 以防有人认为这个问题已经被问到了。我已经读过了。这

我目前正在设计一个用于存储食谱的数据库模式。在这个数据库中,我希望能够标记不同类型的实体(配料、配方发布者、配方等)。所以一个标记有多个n:m关系。如果我使用“三表设计”,这将为我拥有的每种实体类型(配方、成分、发行人)生成表(交叉表)。换句话说,每次我引入一个实体时,我必须为它添加一个交叉表

我正在考虑创建一个表,该表具有所有实体都引用的唯一id,并且在标记表和“唯一id”表之间有一个n:m关系。这样,“唯一id”表和标记表之间只有一个交叉表


以防有人认为这个问题已经被问到了。我已经读过了。这里提到了三张桌子的设计。

我认为你的思路是对的。你描述得很好,你有几个不同的实体。您可以创建一个名为entities的表,其中包含所有公共属性(如果有)。比如说

实体

  • 实体ID
  • 名字
配料

  • 实体ID
  • 数量
接受者

  • 实体ID
  • 其他信息
现在您可以有一个表来标记实体

这个怎么样

类型(主键:类型,设置id[,类型描述])

属性(主键:(设置id,FK:类型),值)


注:粗体/斜体字真的很吸引人

将表格制作成普通的食谱、配料等

那么您的标记表应该如下所示: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
    来切断所有这些“能力”吗

  • 如果您真的想在DB级别强制执行一个标记一个实体约束。。。顺便说一句,至少有一种常见的方法可以在不让FK充当PK的情况下做到这一点:引入标记的“类型”(这对其他功能可能很有用)

  • 按照这些思路,我们可以吃一块蛋糕:

    - - - - - - - - - -
    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)。物品是实际的实物物品,物品是从物品衍生出来的。文章是可以在网站上显示的东西,而项目是