简体   繁体   English

应该在@ManyToMany关系的两边指定@JoinTable吗?

[英]Should @JoinTable be specified in both sides of a @ManyToMany relationship?

I've an entity Course and an entity User . 我有一个实体Course和一个实体User There's a many-to-many relation ship between course and user, since a course can have many users and a user can be enrolled in many courses. 课程和用户之间存在多对多的关系,因为课程可以包含许多用户,并且用户可以在许多课程中注册。 In both entities I've put the @ManyToMany annotation on the specific field, that is, in Course I have: 在两个实体中,我将@ManyToMany注释放在特定字段上,也就是说,在Course I中:

@ManyToMany
private List<RegisteredUser> members;

and in User I have: User我有:

@ManyToMany
private List<Course> coursesTaken;

Now, I know that this kind of many-to-many relationships are usually represented by a third table. 现在,我知道这种多对多关系通常由第三个表表示。 I also know that there's the annotation @JoinTable which allows us to do that. 我也知道@JoinTable的注释允许我们这样做。 What I don't know is if I should add this annotation @JoinTable over both fields in the two different entities or not. 我不知道的是,我是否应该在两个不同实体的两个字段中添加此注释@JoinTable By the way, if I need to add to both, the names need to match right? 顺便说一句,如果我需要添加到两者,名称需要匹配正确吗?

It's actually a good question, and it helps to understand the concept of an "owning" entity because neither side needs a @JoinTable annotation. 这实际上是一个很好的问题,它有助于理解“拥有”实体的概念,因为任何一方都不需要@JoinTable注释。 If you want to prevent both sides from having join tables , a good idea, then you need to have a mappedBy= element on one side. 如果你想阻止双方都有join tables ,一个好主意,那么你需要在一侧有一个mappedBy=元素。 The @JoinTable annotation is used to either specify the table name, or the columns that map the association. @JoinTable注释用于指定表名或映射关联的列。

First look at the Javadoc for @JoinTable : 首先看一下@JoinTableJavadoc

Specifies the mapping of associations. 指定关联的映射。 It is applied to the owning side of an association. 它适用于协会的拥有方。

Whether or not there is a join table is controlled by the mappedBy="name" element of the @ManyToMany annotation. 是否存在join table@ManyToMany注释的mappedBy="name"元素@ManyToMany The Javadoc for mappedBy for the ManyToMany annotation says : ManyToMany注释的mappedByJavadoc说

The field that owns the relationship. 拥有这种关系的领域。 Required unless the relationship is unidirectional. 除非关系是单向的,否则是必需的。

For your (bidirectional) example in Hibernate (5.0.9.Final), if there were only two @ManyToMany annotations and no mappedBy= element, the default will have two Entity tables and two Join Tables : 对于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))

While this is saying that each Entity "owns" its ManyToMany relationship, the extra join table is redundant in the typical use case. 虽然这说明每个实体“拥有”其ManyToMany关系,但额外的join table在典型用例join table是多余的。 However, if I decide to have the Member entity "own" the relationship, then I add the mappedBy= element to the Course entity to specify that it doesn't own the relationship: 但是,如果我决定让Member实体“拥有”该关系,那么我将mappedBy=元素添加到Course实体,以指定它不拥有该关系:

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

Adding @JoinTable(name="Member_Course") to the Member entity doesn't change anything: it's only naming the table the same as it would have been named anyway. @JoinTable(name="Member_Course")Member实体不会改变任何内容:它只是将表命名为无论如何命名。

Since the Course entity no longer owns its ManyToMany relationship, the extra JoinTable will not be created: 由于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))

This is important to the developer because he or she must understand that no relationship is persisted unless it's added to the owning entity, in this case the Member entity. 这对开发人员来说很重要,因为他或她必须明白,除非将关系添加到拥有实体(在本例中为Member实体),否则不会保持任何关系。 However, since this a bidirectional relationship, the developer should be adding both a Course to Member.courses and a Member to Course.members anyway. 然而,由于这是一个双向的关系,开发商应同时添加一个Course ,以Member.coursesMemberCourse.members反正。

So, if you have a bidirectional ManyToMany relationship, which means you have ManyToMany on both entities involved, then you should add a mappedBy="name" on one of them to avoid having a redundant join table . 因此,如果您有bidirectional ManyToMany关系,这意味着您在所涉及的两个实体上都有ManyToMany ,那么您应该在其中一个实体上添加mappedBy="name"以避免使用冗余join table Since it's bidirectional, I don't think it matters which side you make the owning entity. 既然它是双向的,我认为你在哪个方面建立owning实体并不重要。 As always, it's always a good idea to enable the sql logs and see what's going on in the database: 与往常一样,启用sql日志并查看数据库中发生的情况始终是个好主意:

References: 参考文献:

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? ORM映射中的“拥有方”是什么? .

Most efficient way to prevent an infinite recursion in toString()? 防止toString()中无限递归的最有效方法? .

Nope. 不。 Both sides get @ManyToMany , but only one has the @JoinTable 双方都获得@ManyToMany ,但只有一个拥有@JoinTable

More ManyToMany info here 更多ManyToMany信息在这里

For @ManyToMany to work on an an existing schema (not made by Hibernate) you will have to use the @JoinTable annotation on both classes to specify the table and which columns map to Java member variables in the appropriate class. 要使@ManyToMany处理现有模式(不是由Hibernate创建),您必须在两个类上使用@JoinTable批注来指定表,以及哪些列映射到相应类中的Java成员变量。 I think this example may help you with what properties should be passed to the annotation: 我认为这个例子可以帮助你将哪些属性传递给注释:

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

You actually CAN use @JoinTable on both sides and often it makes perfect sense! 你实际上可以在两边都使用@JoinTable,而且它通常很有意义! I am talking out of experience after I had been looking for this solution for weeks. 在我寻找这个解决方案数周后,我正在谈论经验。

Even though all throughout the internet, blogs and articles tell a different story - and the Javadoc of JPA is easily misunderstood (or wrong) in this way. 即使整个互联网,博客和文章都讲述了不同的故事 - 而JPA的Javadoc很容易被这种方式误解(或错误)。 I tried it after seeing this uncommented example in a book for professionals - and it worked. 我在专业书籍中看到这个未注释的例子之后尝试了它 - 并且它起作用了。

How to do it: 怎么做:

Singer-Instrument-Association: Singer side : 歌手 - 乐器协会: 歌手方

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

And exactly the same on the other side! 在另一边完全相同! Instrument side : 仪器方面

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

So, if you address the same join table, "singer_instrument", with the same name, it work's. 因此,如果您使用相同的名称来处理相同的连接表“singer_instrument”,则它可以正常工作。 If you address one join table "singer_instrument" and one join table "instrument-singer" though, it will indead result in two different join tables in the database. 如果您使用一个连接表“singer_instrument”和一个连接表“instrument-singer”,它将会在数据库中导致两个不同的连接表。

This makes a lot of sense, because a many-to-many relationship has no owning side - seen from the database perspective. 这很有意义,因为从数据库的角度来看,多对多关系没有自己的一面。 Owning side means the side, that owns the foreign key of the relationship. 拥有方意味着拥有关系外键的一方。 But neither the table "singer" nor "instrument" have a foreign key referring to each other. 但是表“歌手”和“乐器”都没有外键互相引用。 The foreign keys are inside the neccessary join table between them. 外键位于它们之间的必要连接表内。

The advantage of @JoinTable on both sides of the relation: Let's say, a singer starts to learn a new instrument: You can add the instrument to singer (and vise versa, as it is bidirectional) and update/merge the singer. @JoinTable在关系两边优势 :让我们说,歌手开始学习一种新乐器:你可以将乐器添加到歌手(反之亦然,因为它是双向的)并更新/合并歌手。 The update will update only the singer and the join table. 更新将仅更新歌手和连接表。 It won't touch the instrument-table . 不会碰到仪表

Now the other case - a guitar-course has ended, so you want to remove the connection between the guitar and the former course-participants/singers: After removing the instrument "guitar" from the singers (and vise versa!), you update/merge the instrument. 现在另一个案例 - 吉他课程已经结束,所以你想要删除吉他和前课程参与者/歌手之间的联系:从歌手中取出乐器“吉他”(反之亦然!),你更新/合并文书。 The update will update only the instrument and the join table . 更新将仅更新工具和连接表 It won't touch the singer-table . 不会碰到歌手表

If you had @JoinTable only on one side, you would always have to update/save/delete this side to safely handle the entries in the join table (the relationships between singers and instruments). 如果你只在一边有@JoinTable,你总是需要更新/保存/删除这一边来安全地处理连接表中的条目(歌手和乐器之间的关系)。 In this case, you would have to update each singer, who ended the guitar course. 在这种情况下,你必须更新每个结束吉他课程的歌手。 That is not reflecting the type of relationship properly and can cause performance issues and conflicts during data transaction . 不能正确反映关系的类型,并且可能在数据事务期间导致性能问题冲突

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM