Hibernate/JPA中的ManyToOne与OneToMany区别

77
我目前正在阅读Hibernate文档,关于实体关联的内容,但是我遇到了一些难以理解的问题。从本质上讲,这与ManyToOneOneToMany关联之间的区别有关。尽管我在真实项目中使用过它们,但我仍然不能完全理解它们之间的区别。据我所知,如果一个表/实体与另一个表/实体具有ManyToOne关联,则关联应该来自另一侧的OneToMany。那么,我们应该根据特定情况如何决定选择哪个,并且它如何影响数据库/查询/结果?是否有好的例子?
附言:我认为,如果有人能够解释关联所有者的要点以及双向和单向关联之间的区别,由于其与问题的相关性,这将是有帮助的。

这个回答解决了你的问题吗?一对多,多对一和多对多之间的区别? - crowne
4个回答

100
假设您有一个Order和一个OrderLine。您可以选择在Order和OrderLine之间具有单向的OneToMany关系(Order将拥有OrderLines集合)。或者,您可以选择在OrderLine和Order之间具有ManyToOne关联(OrderLine将引用其Order)。或者,您可以同时选择两者,这种情况下关联变成双向的OneToMany / ManyToOne关联。
您选择的解决方案主要取决于情况以及实体之间的耦合程度。例如,如果用户、公司、提供商都有多个地址,将每个实体与Address之间具有单向关系,并且Address不知道其所有者,这是有意义的。
假设您有一个User和一个Message,其中用户可能有数千条消息。只将其建模为从Message到User的ManyToOne关系可能是有意义的,因为您通常不会要求获取用户的所有消息。虽然关联可以变为双向,但仅为了帮助查询,因为JPQL查询通过浏览它们的关联之间进行实体连接。
在双向关联中,您可能会遇到对象图不一致的情况。例如,订单A将具有一个空的OrderLines集合,但是某些OrderLines将引用订单A。JPA要求始终有一个侧面是所有者侧面,而另一个侧面则是反转侧面。JPA忽略反向面。所有者侧是决定关系的一方。在OneToMany双向关联中,所有者侧必须是多个方面。因此,在上一个示例中,所有者侧将是OrderLine,而JPA将保留线路和订单A之间的关联,因为该线路具有对A的引用。
这样的关联应该被映射如下:
在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;

在 OrderLine 中:

@ManyToOne
private Order parentOrder;

19

虽然以上答案正确,但我会用另一种方式来回答。

@OneToMany@ManyToOne都有两个部分:左侧和右侧。例如:

  • @OneToMany = 'One'是左侧,'Many'是右侧
  • @ManyToOne = 'Many'是左侧,'One'是右侧

使用这个理解的简单关联规则是,左侧代表您正在定义关联的类。

因此,如果您在OrderLine类中定义对Order类的@ManyToOne引用,这意味着许多OrderLine与一个Order类相关联。


12

此外,将 @ManytoOne 作为所有者,在保存关联时只需要 n+1 次查询。其中n是关联的数量(多方)。

而将 @OneToMany 作为所有者,则在插入带有关联(多方)的父实体(一方)时会产生 2*N + 1 次查询。其中一次查询是为了插入关联,另一次查询是为了更新关联实体中的外键。


你能否包含一些 SQL 示例? - parsecer

1
我将通过一个例子来回答。假设您有一个订购或POS系统的设计。然后,每个订单都有订单详细信息(例如产品)。在这种情况下,我们有一个@oneToMany关系。销售和销售明细关系也是如此。
如果我有一个用户表,每个用户都与特定的商店相关联,那么我们可以有许多用户与同一家商店相关联,因此是@manyToOne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接