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

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


答案 1

EDIT 2017-04-29:正如一些注释者所指出的那样,该示例不需要注释属性。实际上,最新版本的Hibernate通过打印以下错误拒绝启动:JoinTablemappedBy

org.hibernate.AnnotationException: 
   Associations marked as mappedBy must not define database mappings 
   like @JoinTable or @JoinColumn

假设您有一个名为的实体和另一个命名的实体,每个项目可以有多个任务。ProjectTask

可以通过两种方式为此方案设计数据库架构。

第一个解决方案是创建一个名为的表和另一个命名的表,并向名为 的任务表中添加一个外键列:ProjectTaskproject_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

该表称为“联接表”。要在 JPA 中实现第二个解决方案,您需要使用注释。例如,为了实现单向一对多关联,我们可以将实体定义为:Project_Tasks@JoinTable

项目实体:

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

任务实体:

@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

注释还允许您自定义联接表的各个方面。例如,我们是否像这样注释了该属性:@JoinTabletasks

@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

@ManyToMany协会

大多数情况下,您需要使用注释来指定多对多表关系的映射:@JoinTable

  • 链接表的名称和
  • 两个外键列

因此,假设您有以下数据库表:

Many-to-many table relationship

在实体中,您将映射此关系,如下所示: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<>();

注释用于通过属性指定表名,以及引用表的外键列(例如 ,)和通过属性引用实体的链接表中的外键列。@JoinTablenamepostjoinColumnspost_tagTaginverseJoinColumns

请注意,注释的级联属性设置为 并且只是因为级联是一个坏主意,因为我们的 DELETE 语句将针对另一个父记录(在本例中为该记录)发出。@ManyToManyPERSISTMERGEREMOVEtagpost_tag

单向关联@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
}

休眠将假定上述实体映射具有以下数据库架构:

Unidirectional @OneToMany JPA association database tables

如前所述,单向 JPA 映射的行为类似于多对多关联。@OneToMany

要自定义链接表,您还可以使用注释:@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_refpost_idpostpost_comment_idpost_comment

单向关联效率不高,因此最好使用双向关联或仅使用侧面关联。@OneToMany@OneToMany@ManyToOne


推荐