JPA“@JoinTable”注释

问题

在哪种情况下,你使用JPA@JoinTable注释?


#1 热门回答(271 赞)

编辑2017-04-29:正如一些评论者指出的那样,JoinTableexample不需要87363282anannotation属性。事实上,最新版本的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

TheProject_Taskstable被称为"连接表"。要在JPA中实现此第二个解决方案,你需要使用@JoinTableannotation。例如,为了实现单向一对多关联,我们可以如下定义我们的实体:
Projectentity:

@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;
    }
}

Taskentity:

@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;
    }

}

这将创建以下数据库结构:

ER Diagram 1

The@JoinTableannotation还允许你自定义连接表的各个方面。例如,如果我们注释了这样的tasks属性:

@JoinTable(
        name = "MY_JT",
        joinColumns = @JoinColumn(
                name = "PROJ_ID",
                referencedColumnName = "PID"
        ),
        inverseJoinColumns = @JoinColumn(
                name = "TASK_ID",
                referencedColumnName = "TID"
        )
)
@OneToMany
private List<Task> tasks;

生成的数据库将变为:

ER Diagram 2

最后,如果要为多对多关联创建模式,则使用连接表是唯一可用的解决方案。


#2 热门回答(13 赞)

它是映射ManyToMany关联的唯一解决方案:你需要在实体表之间使用连接表来映射关联。

当你不想在多方面的表中添加外键时,它也用于OneToMany(通常是单向)关联,从而保持它与一方无关。

hibernate documentation中搜索@JoinTable以获得解释和示例。


#3 热门回答(13 赞)

当一个实体可能是与不同​​类型的父母的几个父/子关系中的孩子时,使用@JoinTable也更清晰。为了跟进Behrang的例子,想象一个Task可以是Project,Person,Department,Study和Process的孩子。

tasktable是否应该拥有5nullable个外键字段?我想不是...