我正在阅读Hibernate关于实体关联的文档,我遇到了一点困难来弄清楚一些事情。它本质上与ManyToOne
和OneToMany
组合的区别有关。虽然我在实际项目中使用过它们,但我不能完全理解它们之间的区别。根据我的理解,如果一个表/实体与另一个表/实体有ManyToOne
关联,那么该关联应该来自另一方的OneToMany
。那么,我们应该如何根据具体情况决定选择哪一个,以及它如何影响数据库/查询/结果?到处都有好的例子吗?
注::我认为这将会很有帮助,因为它与问题相关,如果有人能解释一下协会的所有者的意义以及双向和单向协会的区别。
假设您有一个Order和一个OrderLine。您可以选择在Order和OrderLine之间有一个单向的OneToMany (Order将有一个OrderLine的集合)。或者您可以选择在OrderLine和Order之间有一个多toone关联(OrderLine将有一个对它的Order的引用)。或者您可以选择两者都有,在这种情况下,该关联成为双向的OneToMany/ManyToOne关联。
您选择的解决方案主要取决于情况,以及实体之间的耦合级别。例如,如果一个用户、一个公司、一个提供者都有许多地址,那么在他们和Address之间有一个单向的,并且让Address不知道他们的所有者是谁,这是有意义的。
假设您有一个User和一个Message,其中一个用户可以有数千条消息,将其建模为从Message到User的ManyToOne是有意义的,因为无论如何您很少会请求用户的所有消息。这种关联可以是双向的,只是为了帮助查询,因为JPQL查询通过导航它们的关联来连接实体。
在双向关联中,您可能处于对象图不一致的情况。例如,订单A将有一组空的OrderLines,但是一些OrderLines将有对订单A的引用。JPA强制要求总是将关联的一方作为所有者方,而另一方作为逆方。JPA忽略了反面。所有者一方是决定存在何种关系的一方。在OneToMany双向关联中,所有者方必须是多方。因此,在前面的示例中,所有者端将是OrderLine,并且JPA将保留行与订单A之间的关联,因为行有对A的引用。
这样的关联将被映射为:
in Order:
@OneToMany(mappedBy = "parentOrder") // mappedBy indicates that this side is the
// inverse side, and that the mapping is defined by the attribute parentOrder
// at the other side of the association.
private Set<OrderLine> lines;
in OrderLine:
@ManyToOne
private Order parentOrder;
虽然以上答案是准确的,但我将以另一种方式给出答案。
@OneToMany
和@ManyToOne
都有两个部分;左部分和右部分。例如:
-
@OneToMany
= 'One'为左部分,'Many'为右部分 -
@ManyToOne
= 'Many'为左部分,'One'为右部分
使用这种理解的简单关联规则是,左边部分表示要在其中定义关联的类。
因此,如果您在OrderLine类中定义@ManyToOne
引用Order类,则意味着多个OrderLine关联到一个Order类。
另外,在保存关联时,将@ManytoOne
端作为所有者只需要n+1个查询。其中n是关联数(多侧)。
如果将@OneToMany
作为所有者,在插入具有关联(多侧)的父实体(一侧)时,将导致2*N + 1查询。其中一个查询将用于关联的插入,另一个查询将用于更新关联实体中的外键。
我将通过一个例子来回答。假设您有一个订购系统或POS系统的设计。然后,每个订单都有订单详细信息(例如产品)。在这种情况下,我们有一个@oneToMany
关系。这同样适用于销售和销售细节关系。
如果我有一个用户表,每个用户都绑定到一个特定的商店,那么我们可以有许多用户绑定到同一个商店,因此@manyToOne
。