多对多表应该有一个主键吗?

Posted

技术标签:

【中文标题】多对多表应该有一个主键吗?【英文标题】:Should many to many tables have a primary key? 【发布时间】:2011-05-29 01:54:18 【问题描述】:

如果我有两个具有多对多关系的对象,我通常会在我的数据库模式中使用多对多表对它们进行建模以将两者关联起来。但是该多对多表(或“连接表”)是否应该有自己的主键(整数自动递增)?

例如,我可能有表 A 和 B,每个表都有一个 ID,还有一个名为 A_B 的表,其外键元组为 (A_ID, B_ID)。但是 A_B 是否应该有一个自己的主键自增 ID 列?

添加它有什么好处和坏处?我个人喜欢多对多连接的自然键。但是主键会增加什么额外的好处呢?

【问题讨论】:

***.com/questions/2190272/… 的副本。 那我们应该删除这个问题吗? 【参考方案1】:

如果跟踪多对多关系的表有它自己的主键,并且该键被用作数据库中其他任何地方的外键,那么您将创建对该关系的依赖关系。这种关系永远无法消除。

例如在汽车颜色示例中,如果汽车的颜色曾经停止使用(从多对多关系表中删除),那么任何引用主键的表(即购买历史记录)都会被破坏。

【讨论】:

【参考方案2】:

经常使用术语“连接表”,但我认为我从未见过正确定义或解释过它。我个人避免使用该术语。据我了解,“连接表”是指具有两个外键(或可能超过两个?)的任何表。

我认为在具有多个外键的表中选择键的标准应该与在任何其他表中相同。问问自己需要强制执行哪些依赖项,哪些是独特的和不可约的。根据熟悉度、稳定性和简单性的标准选择键。仅在有充分理由时才添加代理键。

【讨论】:

【参考方案3】:

我同意奥德所说的一切,除了

“它不能合理地用作 外键也是。”

在这种情况下,这是一个选择你的毒药,映射表绝对可以是父母,这只是孩子是否使用多列FK的问题。

以汽车和颜色为例。每年汽车制造商都有一定的颜色托盘,每种型号只有有限数量的这些颜色。多 - 多 :: 汽车模型的颜色

所以现在设计存储新车订单的订单表。很明显,颜色和型号将在订单表上。如果您对这些表中的每一个进行 FK,数据库将允许选择不正确的模型/颜色组合。 (当然,您可以使用代码强制执行此操作,但不能以声明方式执行此操作。)如果您将父表设为多:多表,您将只能获得已指定的组合。

所以您更愿意拥有一个多列 FK 并指向一个基于 ModelID 和 ColorID 构建的 PK,还是您想要一个单列 FK?

选择你的毒药。

编辑

但如果它不是某个东西的父项,则没有表需要代理键。

【讨论】:

【参考方案4】:

这样的代理键只会增加开销。

使用自然键,如果您关心此表中的重复,请将它们设为复合主键。

展开:

在应用程序中,此密钥将无意义,将保持未使用状态。

在数据库中,它将没有任何功能,因为您无法在查询中合理地使用它来获取任何类型的有意义的结果。

它也不能合理地用作外键。

【讨论】:

是的,我能看到的唯一用途是,如果您想将删除限制为一条记录——但这会导致额外查找 ID,假设您有两个外键 ID。我同意。 @ashes999 - 此表(或任何表)中不应有重复的行。如果你不这样做,那么删除一行将只需要两个外键。【参考方案5】:

我已经做到了这两种方式。有时它有利于在以后添加功能。例如,如果曾经有一次表中的一行包含的内容不仅仅是 2 个 id。如果您不缺少空间,我会在其中放一个,因为它不会造成伤害。有时它可能会干扰 ORM 工具,如 hibernate 或 ADO.NET,但那是次要的。

总之... 优点 1. 允许潜在的未来增长。

缺点 1. 空间 2. 混淆了一些ORM工具。

【讨论】:

关于潜在的未来增长,请注意,只要将有意义的数据添加到关联表,它就不仅仅是持久性逻辑。它成为自己的实体。这可能会导致域中的头痛。我认为最好将业务实体与持久性逻辑分开并保持分开。如果您需要将数据添加到关联表中,请从更广泛的角度重新考虑您在做什么以及是否有更好的方法,因为逻辑影响不仅仅是向表中添加列。 我同意。虽然很难想象一个 M:M 关系会成为具有唯一主键的实体的示例。 很公平,我从来没有因为决定这样做而头疼。我有充当 M:M 关系的实体,其中包含其他有用的数据。这些数据有时是在它自己的网页中编辑的,在这种网页中,只有一个 ID 可以方便地传递。 我明白你在说什么。例如,一个允许多个作者的博客可以有一个 authors_post 表,带有一个(后来添加的)author_added_on_date 字段,这样我们就可以回到修订版并查看谁在何时获得了许可。唔。我仍然会说“在需要时添加代理键,而不是之前。” ahes999 - 是的,这正是我所指的那种情况。我同意,如果需要,您可以随时添加。【参考方案6】:

它并没有真正提供任何有用的东西。请记住键的用途,即唯一地引用“某物”。像这样的关联表本身并不是“某物”,而是其他两个已经有键的“某物”的持久性结构。在持久性介质(数据库)之外,它没有任何意义,甚至不应该真正存在或不为人所知(例如在业务领域中),因此(应该)永远没有理由通过以下方式引用它自己的 ID。

【讨论】:

正是我的论点。真实的对象应该有 ID 来识别它们。 @ashes999:是的,转到最初的问题,我真的想不出向这样的表添加单独的主键有什么好处。在我看来,@dko 的建议更多的是风险而不是好处。在某些情况下,它可能会提供立即有价值的东西,但我不会对它打开的门感到满意。

以上是关于多对多表应该有一个主键吗?的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis的多表(多对多)查询

多对多关系的联结表是不是应该具有代理主键?

填充具有访问权限的多对多表

多对多 Spring Boot JPA 未填充多对多表

LINQ to Entities 查询多对多表

(十三)Hibernate中的多表操作:单向多对多