@JoinTable应该在@ManyToMany关系的双方中指定



我有一个实体Course和一个实体User。课程和用户之间存在多对多关系,因为一个课程可以有多个用户,一个用户可以注册多个课程。在这两个实体中,我都@ManyToMany注释放在特定字段上,也就是说,在我拥有Course

@ManyToMany
private List<RegisteredUser> members;

User中,我有:

@ManyToMany
private List<Course> coursesTaken;

现在,我知道这种多对多关系通常由第三个表表示。我也知道有注释@JoinTable允许我们这样做。我不知道的是,我是否应该在两个不同实体的两个字段上@JoinTable添加此注释。顺便说一句,如果我需要添加到两者中,名称需要匹配吗?

这实际上是一个很好的问题,它有助于理解"拥有"实体的概念,因为双方都不需要@JoinTable注释。如果你想防止双方都有 join tables ,一个好主意,那么你需要在一侧有一个mappedBy=元素。@JoinTable批注用于指定表名或映射关联的列。

首先看看Javadoc@JoinTable:

指定关联的映射。它适用于协会的拥有方。

是否存在join table@ManyToMany注释的mappedBy="name"元素控制。用于ManyToMany注释的 mappedBy 的 Javadoc 说:

拥有关系的字段。除非关系是单向的,否则是必需的。

对于Hibernate(5.0.9.Final)中的(双向)示例,如果只有两个@ManyToMany注释并且没有mappedBy=元素,则默认将有两个Entity表和两个Join Tables

Hibernate: create table Course (id bigint not null, primary key (id))
Hibernate: create table Course_Member (Course_id bigint not null, members_id bigint not null, primary key (Course_id, members_id))
Hibernate: create table Member (id bigint not null, primary key (id))
Hibernate: create table Member_Course (Member_id bigint not null, courses_id bigint not null, primary key (Member_id, courses_id))

虽然这是说每个实体"拥有"其ManyToMany关系,但在典型用例中,额外的join table是多余的。但是,如果我决定让Member实体"拥有"关系,则我将mappedBy=元素添加到Course实体以指定它不拥有该关系:

@ManyToMany(mappedBy="courses")
Set<Member> members;

Member 实体添加 @JoinTable(name="Member_Course") 不会更改任何内容:它只是以

与无论如何命名相同的方式命名表。

由于Course实体不再拥有其ManyToMany关系,因此不会创建额外的JoinTable

Hibernate: create table Course (id bigint not null, primary key (id))
Hibernate: create table Member (id bigint not null, primary key (id))
Hibernate: create table Member_Course (members_id bigint not null, courses_id bigint not null, primary key (members_id, courses_id))

这对开发人员很重要,因为他或她必须了解,除非将关系添加到拥有实体(在本例中为Member实体),否则不会保留任何关系。但是,由于这是一种双向关系,因此开发人员无论如何都应该向Member.courses添加一个Course,并为Course.members添加一个Member

因此,如果您有bidirectional ManyToMany关系,这意味着您对所涉及的两个实体都有ManyToMany,那么您应该在其中之一上添加一个mappedBy="name"以避免出现冗余join table。由于它是双向的,我认为你把owning实体的哪一边并不重要。与往常一样,启用 sql 日志并查看数据库中发生的情况始终是一个好主意:

引用:

单向关联和双向关联有什么区别?

关系

所有者在双向关系中是什么意思?

ORM映射中的"拥有方"是什么?

防止 toString() 中无限递归的最有效方法?

您实际上可以在两侧使用@JoinTable,而且通常非常有意义!在我寻找这个解决方案数周之后,我正在谈论经验。

尽管在整个互联网上,博客和文章讲述了一个不同的故事 - 而JPA的Javadoc很容易以这种方式被误解(或错误)。在一本面向专业人士的书中看到这个未加注释的示例后,我尝试了它 - 它奏效了。

怎么做:

歌手-乐器-协会:歌手方面

@ManyToMany 
@JoinTable(name = "singer_instrument", joinColumns =
@JoinColumn(name = "SINGER_ID"), inverseJoinColumns = @JoinColumn(name = "INSTRUMENT_ID")) 
public Set<Instrument> instruments;

另一边也一样!仪器侧

@ManyToMany
@JoinTable(name = "singer_instrument",
joinColumns = @JoinColumn(name = "INSTRUMENT_ID"),
inverseJoinColumns = @JoinColumn(name = "SINGER_ID"))
public Set<Singer> singers;

因此,如果您使用相同的名称寻址同一个连接表"singer_instrument",它就可以工作。但是,如果寻址一个连接表"singer_instrument"和一个连接表"instrument-singer",它将在数据库中生成两个不同的连接表。

这很有意义,因为从数据库的角度来看,多对多关系没有拥有方。拥有方是指拥有关系外的一方。但是表"歌手"和"乐器"都没有相互引用的外键。外键位于它们之间的必要连接表中

关系双方@JoinTable的优势:假设一个歌手开始学习一种新的乐器:您可以将乐器添加到歌手(反之亦然,因为它是双向的)并更新/合并歌手。更新将仅更新歌手和联接表。它不会碰到仪器表

现在另一种情况 - 吉他课程已经结束,所以你想删除吉他和以前的课程参与者/歌手之间的联系:从歌手中删除乐器"吉他"后(反之亦然!),你更新/合并乐器。更新将仅更新仪器和连接表。它不会碰到歌手桌

如果只有一侧@JoinTable,则始终必须更新/保存/删除此侧,以安全地处理连接表中的条目(歌手和乐器之间的关系)。在这种情况下,您必须更新结束吉他课程的每个歌手。这不能正确反映关系的类型,并且可能会导致数据事务期间的性能问题和冲突。

不。双方都@ManyToMany,但只有一方有@JoinTable

更多多对多信息在这里

要使@ManyToMany处理现有模式(不是由 Hibernate 创建的),您必须在两个类上使用 @JoinTable 注释来指定表以及哪些列映射到相应类中的 Java 成员变量。我认为此示例可以帮助您确定应将哪些属性传递给注释:

https://dzone.com/tutorials/java/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html

最新更新