- 在双向多对多关系中设置MappedBy的原因是什么?
- 当一张表有大量记录而另一张表只有少量记录时,将mappedBy放在哪一侧更好?
这实际上是一个很好的问题,并且有助于理解“拥有”实体的概念。如果您想要防止双向关系中的两个方向都有join tables
,那么您需要在一侧使用mappedBy=
元素,这是一个好主意。
是否有join table
由@ManyToMany
注释的mappedBy="name"
元素控制。 关于ManyToMany
注释的mappedBy的Javadoc说:
拥有关系的字段。除非关系是单向的,否则必填。
对于您的(双向)示例,如果只有两个@ManyToMany
注释而没有mappedBy=
元素,则默认情况下将有两个Entity
表和两个Join Tables
:
Hibernate: create table SideA (id bigint not null, primary key (id))
Hibernate: create table SideA_SideB (sidea_id bigint not null, sidebs_id bigint not null, primary key (sidea_id, sidebs_id))
Hibernate: create table SideB (id bigint not null, primary key (id))
Hibernate: create table SideB_SideA (sideb_id bigint not null, sideas_id bigint not null, primary key (sideb_id, sideas_id))
ManyToMany
关系,但在典型情况下,额外的join table
是多余的,而且Javadoc说你需要一个mappedBy
注释。如果我决定让SideA“拥有”这个关系,那么我需要在SideB实体中添加mappedBy=
元素来指定它不拥有这个关系:@Entity
public class SideA {
@ManyToMany
Set<SideB> sidebs;
}
@Entity
public class SideB {
@ManyToMany(mappedBy="sidebs")
Set<SideA> sideas;
}
由于SideB实体不再拥有它的ManyToMany
关系,因此不会创建额外的JoinTable
:
Hibernate: create table SideA (id bigint not null, primary key (id))
Hibernate: create table SideB (id bigint not null, primary key (id))
Hibernate: create table SideA_SideB (sideas_id bigint not null, sidebs_id bigint not null, primary key (sideas_id, sidebs_id))
SideA
实体),否则不会保存任何关系。因此,如果您有一个双向的ManyToMany
关系,这意味着涉及到两个实体的ManyToMany
,那么应根据Javadoc在其中一个实体上添加mappedBy="name"
,以避免出现冗余的join table
。
关于选择哪一方作为拥有实体的一方,没有正确答案,这取决于你的系统认为什么最好。只有在将条目放入拥有方时,关系才会被持久化,因此你必须问自己,你更常更改 SideA
的列表还是 SideB
的列表。如果 SideA
拥有关系,则通过将 SideB
实例从 SideA
实例中添加或删除来更新关系,但如果你有一个 SideB
的 SideA
实例列表需要持久化,则需要迭代列表并更改列表中每个 SideA
实例。
像往常一样,启用 SQL 日志并查看数据库中正在发生的事情总是一个好主意:
编辑:如果你有一个只创建单个联接表且没有设置 mappedBy
的持久性提供程序,则必须查看文档以确定哪一方“拥有”关系。可能是两者都不拥有,也可能是两者都拥有,更新任何一方都将持久化实体。
参考资料:
mappedBy
将双向关系的两个方向连接起来。您需要将mappedBy
放在关系的所有者上,而不是基于某个记录拥有多少(即面向对象设计)。您可以在任何JPA教程和文档中找到这些信息。
mappedBy
放在了关系的反向端。 - Jack
@JoinTable
注释将影响联接表的创建,本答案不涉及此问题。 - K.Nicholas