为啥 Hibernate 文档建议将连接表用于一对多关系?
Posted
技术标签:
【中文标题】为啥 Hibernate 文档建议将连接表用于一对多关系?【英文标题】:Why do Hibernate docs recommend to use a join table for a one-to-many relation?为什么 Hibernate 文档建议将连接表用于一对多关系? 【发布时间】:2011-07-12 15:12:02 【问题描述】:我认为在数据库中建模一对多关系的常用方法是通过外键关系(即一个客户有很多订单 -> 订单表获得对客户表的 FK 引用)。
但是,Hibernate 建议使用连接表来为此类关系建模:
在所拥有的中使用外键列的单向一对多 实体并不常见,也不是很推荐。我们强烈 建议您对这种关联使用连接表(如 在下一节中解释)。这种关联被描述 通过@JoinColumn。
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping-association
为什么“不推荐”。我认为使用 FK 是标准,而连接表仅用于多对多关系?
我不喜欢创建连接表,因为数据模型看起来像是多对多的关系,而实际上它是一对多的。
Hibernate 文档中此建议的原因是什么?
【问题讨论】:
注意:这与问题***.com/questions/2095998/…有关。但是,这询问了如何避免连接表;我在问为什么建议使用一个。 【参考方案1】:这个问题已在 Hibernate 论坛上提出并回答:https://forum.hibernate.org/viewtopic.php?t=954178&highlight=unidirectional+null+foriegn+foreign+key。这似乎不是 DB 设计的问题,而是 Hibernate 的功能问题。
【讨论】:
【参考方案2】:您拥有 postet 的文档中的引用描述了 单向 @OneToMany 关联,这是另一回事。在这样的关联中,您只有 Customer 对 Orders 的引用,反之则没有。因此,应该使用连接表来映射这种关联,其中包含每个客户的订单集合。
我猜您正在考虑的关联更可能是 @ManyToOne 关联,具有从 Order 到 Customer 的引用。
请注意,如果要建模双向关联,可以使用@OneToMany 注解中的“mappedBy”属性。
【讨论】:
抱歉,无法关注您。是的,我在考虑只引用“客户->(订单列表)”。你指的是什么“这是一个不同的东西”?我想我需要一个一对多的关联,这就是我引用@OneToMany 部分的原因。 我怀疑您正在考虑的是一种 双向 关系,其中 Order 具有标识其拥有的 Customer 的属性,而 Customer 具有列出其拥有的 Orders 的属性。在这种情况下,关于 单向 关系的评论不适用,外键很好。 我认为针对单向一对多的外键的警告是存在的,因为它涉及到表中有一个列没有映射到相应实体中的任何内容,这有点奇怪.该列缺少映射表明该关系不是 Order 的固有部分,在这种情况下,为什么该列在 Order 的表中? 因为它不是一个答案,只是乔治完美答案的一个小补充。【参考方案3】:我不能与任何权威人士交谈,但我一直认为,对于 单向 关系,您的订单更有可能处于多个此类关系的接收端。这也增加了 Order 在其中一些列中具有空值的可能性,因为 Order 已经创建,但是可以引用 Order 的其他对象要么还不存在,要么永远不会存在。就这一点而言,将 FK 列移到另一个表是标准化的问题。还有一个事实是它更好地反映了对象关系。在 Foo -> Bar 的单向一对一中,您希望在 Foo 中找到 FK,而不是在 Bar 中,因为这是对象模型中的所有权所在。这同样适用于来自客户 -> 订单的单一一对多。查看对象模型,您不会期望在 Order 中看到所有权,因此也不会在 Order 表中。
【讨论】:
【参考方案4】:Hibernate 文档中的上一部分介绍了双向一对多关系,并描述了您可能习惯的内容,以及多实体上的标准外键。正如其他人所说,仅当您明确需要单向关系时,此答案才合适。
如果多方一定不知道这种关系,你只会想要单向性。这意味着多方面的类几乎按照定义不能具有表示关系的属性。所以把这个问题想象成问“我如何在不使用正常方法的情况下表示一对多关系”。
想要这样的单向关系当然有些不寻常,但我可以看到您可能出于解耦、安全、审计或不变性的原因需要它。例如,假设您正在对临床试验进行建模,并且您的课程是患者和药物,并且在试验期间您将一组药物中的一种分配给每位患者。您希望在 Patient 上运行的任何逻辑与分配给它们的 Medication 完全解耦。因此,您无需像通常那样使用 Patient.setMedication(),而是创建连接类 MedicationPatientMap 并调用 drug.getMedicationPatientMap().addPatient(patient)。然后,您可以通过药物方面的逻辑控制对患者的一对多关系的药物访问。
我不认为 Customer-Order 是一个很好的例子,因为通常我们的订单心理模型期望客户可以通过它联系到。事实上,大多数时候你不是
【讨论】:
以上是关于为啥 Hibernate 文档建议将连接表用于一对多关系?的主要内容,如果未能解决你的问题,请参考以下文章