jpa 是否应该在@ManyToMany关系的两端指定@JoinTable?

n8ghc7c1  于 8个月前  发布在  其他
关注(0)|答案(4)|浏览(78)

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

@ManyToMany
private List<RegisteredUser> members;

User中,我有:

@ManyToMany
private List<Course> coursesTaken;

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

nhjlsmyf

nhjlsmyf1#

这实际上是一个很好的问题,它有助于理解“拥有”实体的概念,因为双方都不需要@JoinTable注解。如果你想防止两边都有join tables,这是一个好主意,那么你需要在一边有一个mappedBy=元素。@JoinTable注解用于指定表名或Map关联的列。
先来看看Javadoc for @JoinTable
指定关联的Map。它适用于关联的所有方。
是否存在join table@ManyToMany注解的mappedBy="name"元素控制。Javadoc for mappedBy的ManyToMany注解说:
拥有关系的字段。除非关系是单向的,否则为必填项。
对于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;

@JoinTable(name="Member_Course")添加到Member实体不会改变任何内容:它只是将表命名为与它本来的名称相同的名称。
由于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实体),否则关系不会持久化。然而,由于这是一个双向关系,开发人员无论如何都应该添加**CourseMember.coursesMemberCourse.members
所以,如果你有一个bidirectionalManyToMany关系,这意味着你在涉及的两个实体上都有ManyToMany,那么你应该在其中一个实体上添加一个mappedBy="name",以避免冗余的join table。因为它是双向的,所以我认为在哪一边创建owning实体并不重要。像往常一样,启用SQL日志并查看数据库中发生的事情总是一个好主意:
参考文献:
What is the difference between Unidirectional and Bidirectional associations?
What does relationship owner means in bidirectional relationship?
What is the “owning side” in an ORM mapping?
Most efficient way to prevent an infinite recursion in toString()?

ifmq2ha2

ifmq2ha22#

你实际上可以在两边使用@JoinTable,而且通常它是完全有意义的!在我寻找这个解决方案几个星期之后,我说的是经验。

尽管在整个互联网上,博客和文章讲述了一个不同的故事-JPA的Javadoc很容易被误解(或错误)。我在一本专业人士的书中看到这个未加评论的例子后尝试了一下--而且效果很好。

如何做:

歌手-乐器-协会:歌手侧

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

另一边也是一样!** Jmeter 侧**:

@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”,则会在数据库中产生两个不同的连接表。
这很有意义,因为从数据库的Angular 来看,多对多关系没有拥有方。Owning一方是指拥有关系的foreign key的一方。但是表“singer”和“instrument”都没有指向彼此的外键。外键位于它们之间的连接表中。
@JoinTable在关系两边的
优势:比如说,一个歌手开始学习一种新乐器:您可以将乐器添加到歌手(反之亦然,因为它是双向的)并更新/合并歌手。更新将只更新歌手和连接表。它不会碰到仪器桌。
现在另一种情况-吉他课程已经结束,所以你想删除吉他和前课程参与者/歌手之间的连接:从歌手身上去掉乐器“吉他”后(反之亦然!),则更新/合并仪器。更新将
仅更新仪器 * 和连接表 *。它不会碰到歌手的table。
如果你只在一边有@JoinTable,你总是需要更新/保存/删除 * 这一边 * 来安全地处理连接表中的条目(歌手和乐器之间的关系)。在这种情况下,你必须更新 * 每个 * 歌手,谁结束了吉他课程。这是没有正确反映关系类型,可能导致性能问题数据交易期间的冲突

kpbpu008

kpbpu0083#

不。双方都得到@ManyToMany,但只有一方有@JoinTable
More ManyToMany info here

gr8qqesn

gr8qqesn4#

要让@ManyToMany在现有的模式(不是由Hibernate创建的)上工作,您必须在两个类上使用@JoinTable注解来指定表以及哪些列Map到相应类中的Java成员变量。我认为这个例子可以帮助你了解应该传递给annotation的属性:
https://dzone.com/tutorials/java/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html

相关问题