nbr*_*bro 8 java entity-relationship many-to-many hibernate jpa
我有一个实体Course和一个实体User.有一个多到许多课程和用户之间的关系的船,因为一门课程可以有很多的用户,并且用户可以在许多课程中注册.在两个实体中,我都将@ManyToMany注释放在特定字段上,也就是说,Course我已经:
@ManyToMany
private List<RegisteredUser> members;
Run Code Online (Sandbox Code Playgroud)
在User我有:
@ManyToMany
private List<Course> coursesTaken;
Run Code Online (Sandbox Code Playgroud)
现在,我知道这种多对多关系通常由第三个表表示.我也知道有注释@JoinTable可以让我们这样做.我不知道的是,我是否应该@JoinTable在两个不同实体的两个字段中添加此注释.顺便说一句,如果我需要添加到两者,名称需要匹配正确吗?
K.N*_*las 13
这实际上是一个很好的问题,它有助于理解"拥有"实体的概念,因为任何一方都不需要@JoinTable注释.如果你想防止双方都有join tables一个好主意,那么你需要mappedBy=在一边有一个元素.该@JoinTable注释用于任一指定表名或映射的关联列.
首先看一下@JoinTable的Javadoc:
指定关联的映射.它适用于协会的拥有方.
是否存在join table由注释的mappedBy="name"元素控制@ManyToMany.用于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))
Run Code Online (Sandbox Code Playgroud)
虽然这是说每个实体"拥有"它的ManyToMany关系,但join table在典型的用例中额外是多余的.但是,如果我决定让Member实体"拥有"该关系,那么我将该mappedBy=元素添加到Course实体以指定它不拥有该关系:
@ManyToMany(mappedBy="courses")
Set<Member> members;
Run Code Online (Sandbox Code Playgroud)
添加@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))
Run Code Online (Sandbox Code Playgroud)
这对开发人员很重要,因为他或她必须明白,除非将关系添加到拥有实体(在本例中为Member实体),否则不会保持关系.然而,由于这是一个双向的关系,开发商应该将两者一Course来Member.courses和Member到Course.members反正.
所以,如果你有一个bidirectional ManyToMany关系,这意味着你有ManyToMany两个涉及的实体,那么你应该mappedBy="name"在其中一个上添加一个,以避免冗余join table.既然它是双向的,我认为你制造owning实体的哪一方面并不重要.与往常一样,启用sql日志并查看数据库中发生的情况始终是个好主意:
参考文献:
您实际上可以在两侧使用 @JoinTable并且通常很有意义!在我一直在寻找这个解决方案数周之后,我说的是经验之谈。
尽管在整个互联网上,博客和文章讲述了一个不同的故事 - JPA 的 Javadoc 很容易以这种方式被误解(或错误)。我在一本专业书籍中看到这个未注释的例子后尝试了它 - 它奏效了。
怎么做:
歌手-乐器-协会: 歌手方面:
@ManyToMany
@JoinTable(name = "singer_instrument", joinColumns =
@JoinColumn(name = "SINGER_ID"), inverseJoinColumns = @JoinColumn(name = "INSTRUMENT_ID"))
public Set<Instrument> instruments;
Run Code Online (Sandbox Code Playgroud)
另一边完全一样! 仪表端:
@ManyToMany
@JoinTable(name = "singer_instrument",
joinColumns = @JoinColumn(name = "INSTRUMENT_ID"),
inverseJoinColumns = @JoinColumn(name = "SINGER_ID"))
public Set<Singer> singers;
Run Code Online (Sandbox Code Playgroud)
因此,如果您使用相同的名称处理同一个连接表“singer_instrument”,它就可以工作。但是,如果您处理一个连接表“singer_instrument”和一个连接表“instrument-singer”,它将在数据库中导致两个不同的连接表。
这很有意义,因为多对多关系没有拥有方——从数据库的角度来看。拥有方是指拥有关系外键的一方。但是表“singer”和“instrument”都没有相互引用的外键。外键位于它们之间的必要连接表内。
@JoinTable 在关系双方的优势:假设歌手开始学习一种新乐器:您可以将乐器添加到歌手(反之亦然,因为它是双向的)并更新/合并歌手。更新将只更新歌手和连接表。它不会接触仪器表。
现在另一种情况 - 吉他课程已经结束,因此您想要删除吉他与前课程参与者/歌手之间的联系:从歌手中删除乐器“吉他”(反之亦然!),您更新/合并仪器。更新将只更新仪器和连接表。它不会碰到歌手桌。
如果您只在一侧有 @JoinTable,您将始终必须更新/保存/删除这一侧才能安全地处理连接表中的条目(歌手和乐器之间的关系)。在这种情况下,您必须更新结束吉他课程的每个歌手。这不能正确反映关系类型,并可能导致数据事务期间出现性能问题和冲突。
| 归档时间: |
|
| 查看次数: |
6388 次 |
| 最近记录: |