有什么区别:
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
private List<Branch> branches;
...
}
和
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY,
mappedBy = "companyIdRef")
private List<Branch> branches;
...
}
9条答案
按热度按时间arknldoa1#
注解
@JoinColumn
指示此实体是关系的 * 所有者 *(即:对应的表有一个列,该列有指向被引用表的外键),而属性mappedBy
指示此端的实体是关系的逆,所有者驻留在“other”实体中。这也意味着可以从用“mappedBy”注解的类访问另一个表(完全双向关系)。特别是,对于问题中的代码,正确的注解应该如下所示:
oxiaedzo2#
**
@JoinColumn
可用于关系的两端。**问题是关于在@OneToMany
端使用@JoinColumn
(罕见情况)。此处的要点是 * 物理信息重复 *(列名)沿着 * 未优化的SQL查询,该查询将生成一些额外的UPDATE
语句 *。根据documentation:
由于在JPA规范中,多对一(几乎)总是双向关系的所有者方,因此一对多关联用
@OneToMany(mappedBy=...)
进行注解Troop
与Soldier
之间是双向的一对多关系,通过roop属性,不需要在mappedBy
端定义任何物理Map。若要Map双向一对多,并将一对多方作为拥有方,必须删除
mappedBy
元素,并将多对一个@JoinColumn
设置为insertable
,将updatable
设置为false。此解决方案未经优化,将生成一些额外的UPDATE
语句。kd3sttzy3#
单向一对多关联
如果将
@OneToMany
注解与@JoinColumn
一起使用,则具有单向关联,如下图中的Post
父实体和PostComment
子实体之间的关联:使用单向一对多关联时,只有父端Map该关联。
在此示例中,只有
Post
实体会定义@OneToMany
与PostComment
子实体的关联:双向一对多关联
如果您使用
@OneToMany
与mappedBy
属性集,则具有双向关联。在我们的示例中,Post
实体具有PostComment
子实体的集合,并且子PostComment
实体具有对父Post
实体的引用,如下图所示:在
PostComment
实体中,post
实体属性Map如下:我们将
fetch
属性显式设置为FetchType.LAZY
的原因是,默认情况下,所有@ManyToOne
和@OneToOne
关联都是急切获取的,这可能会导致N+1查询问题。在
Post
实体中,comments
关联Map如下:@OneToMany
注解的mappedBy
属性引用子PostComment
实体中的post
属性,这样,Hibernate就知道双向关联是由@ManyToOne
端控制的,该端负责管理此表关系所基于的外键列值。对于双向关联,还需要两个实用程序方法,如
addChild
和removeChild
:这两种方法确保双向关联的两端同步。如果两端不同步,Hibernate不能保证关联状态的更改会传播到数据库。
选择哪一个?
单向
@OneToMany
关联的性能不太好,因此应该避免使用它。您最好使用双向
@OneToMany
,因为它效率更高。ukxgm1gy4#
我不同意奥斯卡·洛佩斯的公认答案,这个答案是不准确的!
不是
@JoinColumn
指示该实体是关系的所有者,而是@ManyToOne
注解(在他的示例中)。@ManyToOne
、@OneToMany
和@ManyToMany
等关系注解告诉JPA/Hibernate**创建一个Map。**默认情况下,这是通过一个单独的连接表完成的。@联接列
@JoinColumn
的用途是创建一个 * 联接列 *(如果不存在)。如果存在,则此注解可用于 * 命名 * 联接列。Map者
MappedBy
参数的用途是指示JPA:请勿创建另一个联接表,因为此关系的“相反”实体已Map此关系。请记住:
MappedBy
是关系注解的一个属性,其目的是生成一种机制来关联两个实体,默认情况下,它们通过创建一个连接表来关联两个实体。MappedBy
在一个方向上停止该过程。不使用
MappedBy
的实体被认为是关系的 * 所有者 ,因为Map的机制是通过对外键字段使用三个Map注解中的一个在其类中指定的。这不仅指定了Map的性质,而且还指示了连接表的创建。此外,通过在外键上应用@JoinColumn注解也存在抑制连接表的选项,该注解将外键保留在所有者实体的表内。总结一下:
@JoinColumn
创建新的联接列或重命名现有的联接列;而X1 M1 N1 X参数与另一(子)类的关系注解协作工作,以便通过连接表或通过在所有者实体的关联表中创建外键列来创建Map。为了说明
MapppedBy
是如何工作的,请考虑下面的代码。如果删除MappedBy
参数,那么Hibernate实际上会创建两个连接表!为什么?因为多对多关系中存在对称性,Hibernate没有理由选择一个方向而不是另一个方向。因此,我们使用
MappedBy
来告诉Hibernate,我们已经选择了另一个*实体来指示两个实体之间关系的Map。在所有者类(见下文)中添加@JoinColumn(name =“driverID”)将阻止创建连接表,而是在汽车表中创建driverID外键列来构造Map:
lmvvr0a85#
注解mappedBy理想情况下应始终用于双向关系的父类(Company类),在这种情况下,它应位于指向子类(分支类)成员变量“company”的Company类中
注解**@JoinColumn**用于指定用于连接实体关联的Map列,此注解可用于任何类(父类或子类),但理想情况下应仅在一侧使用(父类或子类,而不是在两者中)。在本例中,我在双向关系的子类侧(分支类)使用了此注解,以指示分支类中的外键。
下面是工作示例:
父类,公司
子类,分支
unguejic6#
我只想补充一点,
@JoinColumn
并不一定要像this答案所建议的那样与 * 物理信息位置 * 相关,即使父表没有指向子表的表数据,也可以将@JoinColumn
与@OneToMany
组合在一起。单向一对多,无反向多对一,无连接表
它似乎只在
JPA 2.x+
中可用。当你希望子类只包含父类的ID,而不是一个完整的on引用时,它很有用。hmmo2u0o7#
让我简单点说。
您可以在任何一端使用**@JoinColumn**,而不考虑Map。
让我们把它分成三种情况。
1)从分支到公司的单向Map。
2)从公司到分支的双向Map。
3)仅限从公司到分支的单向Map。
所以任何用例都属于这三个类别。所以让我来解释一下如何使用**@JoinColumn和mappedBy**。
1)从分支到公司的单向Map。
在分支表中使用JoinColumn
2)从公司到分支的双向Map。
在Company表中使用mappedBy,如@Mykhaylo Adamovych的答案所述。
3)公司到分支的单向Map。
只需在Company表中使用**@JoinColumn**即可。
这表示在基于外键“courseId”Map的branches表中,获取所有分支的列表。注意:在这种情况下,您不能从分支获取公司,从公司到分支机构只存在单向Map。
klr1opcd8#
JPA是一个分层的API,不同的层有自己的注解。最高层是(1)实体层,它描述持久类,然后是(2)关系数据库层,它假设实体被Map到关系数据库,以及(3)Java模型。
1级注解:
@Entity
、@Id
、@OneToOne
、@OneToMany
、@ManyToOne
、@ManyToMany
。您可以单独使用这些高级注解在应用程序中引入持久性。但之后您必须根据JPA所做的假设创建数据库。这些注解指定实体/关系模型。二级注解:
@Table
,@Column
,@JoinColumn
,...如果您不满意JPA的预设值,或需要Map至现有数据库,则会影响从实体/属性到相关式数据库表格/栏的Map。这些注解可视为实作注解,它们指定Map的执行方式。在我看来,最好是尽可能多地坚持高级别的注解,然后根据需要引入低级别的注解。
要回答这些问题:
@OneToMany
/mappedBy
是最好的,因为它只使用来自实体域的注解。@oneToMany
/@JoinColumn
也很好,但它使用了一个实现注解,而这并不是严格必要的。l2osamch9#
这将给予以下休眠日志
还有
这将给予下面的Hibernate日志
我们可以清楚地看到
@joinColumn
将导致额外的更新查询。因此,您不需要将父实体显式设置为子实体,这是我们在使用mappedBy
将子实体与父实体一起保存时必须执行的操作