在哪种情况下,您使用JPA @JoinTable
注释吗?
答案 0 :(得分:303)
EDIT 2017-04-29 :正如一些评论者指出的那样,JoinTable
示例不需要mappedBy
注释属性。事实上,最新版本的Hibernate通过打印以下错误拒绝启动:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
让我们假设你有一个名为Project
的实体和另一个名为Task
的实体,每个项目都可以有很多任务。
您可以通过两种方式为此方案设计数据库架构。
第一个解决方案是创建一个名为Project
的表和另一个名为Task
的表,并将一个外键列添加到名为project_id
的任务表中:
Project Task
------- ----
id id
name name
project_id
这样,就可以确定任务表中每一行的项目。如果使用此方法,则在实体类中不需要连接表:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
另一种解决方案是使用第三个表格,例如Project_Tasks
,并存储该表中项目和任务之间的关系:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
Project_Tasks
表称为“连接表”。要在JPA中实现此第二个解决方案,您需要使用@JoinTable
注释。例如,为了实现单向一对多关联,我们可以将这些实体定义为:
Project
实体:
@Entity
public class Project {
@Id
@GeneratedValue
private Long pid;
private String name;
@JoinTable
@OneToMany
private List<Task> tasks;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
}
Task
实体:
@Entity
public class Task {
@Id
@GeneratedValue
private Long tid;
private String name;
public Long getTid() {
return tid;
}
public void setTid(Long tid) {
this.tid = tid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这将创建以下数据库结构:
@JoinTable
注释还允许您自定义连接表的各个方面。例如,我们是否注释了tasks
属性,如下所示:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
结果数据库将成为:
最后,如果要为多对多关联创建架构,则使用连接表是唯一可用的解决方案。
答案 1 :(得分:13)
这是映射ManyToMany关联的唯一解决方案:您需要在实体表之间使用连接表来映射关联。
当你不想在多方面的表中添加外键时,它也用于OneToMany(通常是单向)关联,因此保持它与一方无关。
在hibernate documentation中搜索@JoinTable以获取解释和示例。
答案 2 :(得分:13)
当一个实体可能是具有不同类型的父母的几个父/子关系中的孩子时,使用@JoinTable
也更清晰。为了跟进Behrang的例子,想象一个任务可以是项目,人员,部门,研究和过程的孩子。
task
表是否有5个nullable
个外键字段?我想不是......
答案 3 :(得分:4)
它可以让你处理多对多的关系。例如:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Join Table允许您使用以下方法创建映射:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
将创建一个表:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
答案 4 :(得分:3)
@ManyToMany
关联通常,您需要使用@JoinTable
注释来指定多对多表关系的映射:
因此,假设您具有以下数据库表:
在Post
实体中,您将映射此关系,如下所示:
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Tag> tags = new ArrayList<>();
@JoinTable
批注用于通过name
属性以及引用post
表的外键列(例如joinColumns
)来指定表名。 )和post_tag
链接表中的外键列,该列通过Tag
属性引用了inverseJoinColumns
实体。
请注意,
@ManyToMany
批注的级联属性设置为PERSIST
和MERGE
只是因为级联REMOVE
是一个坏主意,因为我们将发出DELETE语句对于另一个父记录,在我们的情况下为tag
,而不是post_tag
记录。有关此主题的更多详细信息,请查看this article。
@OneToMany
关联缺少@OneToMany
映射的单向@JoinColumn
关联的行为类似于多对多表关系,而不是一对多。
因此,假设您具有以下实体映射:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters removed for brevity
}
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
@GeneratedValue
private Long id;
private String review;
//Constructors, getters and setters removed for brevity
}
Hibernate将为上述实体映射采用以下数据库架构:
正如已经说明的那样,单向@OneToMany
JPA映射的行为就像多对多关联。
要自定义链接表,还可以使用@JoinTable
批注:
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JoinTable(
name = "post_comment_ref",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "post_comment_id")
)
private List<PostComment> comments = new ArrayList<>();
现在,链接表将被称为post_comment_ref
,对于post_id
表,外键列将为post
,对于post_comment_id
,外键列将为post_comment
。 @OneToMany
表。
单向
@OneToMany
关联效率不高,因此最好使用双向@ManyToOne
关联或仅使用std::queue<Event*> events; // ... while(hasUnhandledEvents()) { Event e = pollEvent(); // ... handle event }
端。请查看this article,以获取有关此主题的更多详细信息。