어떤 경우에 JPA @JoinTable 주석을 사용합니까?


답변:


351

편집 2017-04-29 : 일부 주석 작성자가 지적한 것처럼 JoinTable예제에는 mappedBy주석 속성이 필요하지 않습니다 . 사실, 최신 버전의 최대 절전 모드는 다음 오류를 인쇄하여 시작을 거부합니다.

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

}

다음과 같은 데이터베이스 구조가 생성됩니다.

응급실 다이어그램 1

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

결과 데이터베이스는 다음과 같습니다.

응급실 다이어그램 2

마지막으로 다 대다 연관에 대한 스키마를 작성하려는 경우 결합 테이블을 사용하는 것이 유일하게 사용 가능한 솔루션입니다.


1
첫 번째 방법을 사용하면 병합 전에 프로젝트에 내 작업으로 채워진 각 작업과 상위 프로젝트로 채워진 모든 작업이 있지만 모든 항목은 내 작업 수에 따라 복제됩니다. 두 개의 작업이있는 프로젝트가 데이터베이스에 두 번 저장됩니다. 왜 ?
MaikoID

업데이트 내 데이터베이스에 항목이 중복되어 있지 않습니다. 최대 절전 모드가 왼쪽 외부 조인으로 선택되어 있으며 이유를 모르겠습니다 ..
MaikoID

2
@JoinTable/@JoinColumn와 같은 필드에 주석을 달 수 있다고 생각 합니다 mappedBy. 올바른 예는 mappedByin을 유지하고 로 (또는 그 반대로) Project이동해야 @JoinColumn합니다.Task.project
Adrian Shum

2
좋은! 하지만 추가 질문이 다음 테이블에 가입하면 Project_Tasks요구 nameTask세 개의 열이되는,뿐만 아니라 : project_id, task_id, task_name, 어떻게 이것을 달성하기 위해?
macemers

5
이 오류를 방지하기 위해 두 번째 사용 예에서 mapBy를 매핑하지 않았어야한다고 생각합니다.Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
karthik m

14

@JoinTable엔터티가 다른 유형의 부모와 여러 부모 / 자식 관계에서 자식 일 수있는 경우 에도 사용 하는 것이 더 깨끗합니다 . Behrang의 모범을 따르기 위해 Task가 Project, Person, Department, Study 및 Process의 자식이 될 수 있다고 상상해보십시오.

task테이블에 5 개의 nullable외래 키 필드 가 있어야합니까 ? 나는 그렇게 생각하지 않는다...


14

ManyToMany 연관을 맵핑하는 유일한 솔루션입니다. 연관을 맵핑하려면 두 엔티티 테이블 사이에 결합 테이블이 필요합니다.

또한 많은면의 테이블에 외래 키를 추가하지 않기 위해 OneToMany (일반적으로 단방향) 연결에도 사용되므로 한쪽과 독립적으로 유지하십시오.

설명 및 예제 는 최대 절전 모드 설명서 에서 @JoinTable을 검색하십시오 .


4

다 대 다 관계를 처리 할 수 ​​있습니다. 예:

Table 1: post

post has following columns
____________________
|  ID     |  DATE   |
|_________|_________|
|         |         |
|_________|_________|

Table 2: user

user has the following columns:

____________________
|     ID  |NAME     |
|_________|_________|
|         |         |
|_________|_________|

조인 테이블을 사용하면 다음을 사용하여 매핑을 만들 수 있습니다.

@JoinTable(
  name="USER_POST",
  joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
  inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))

테이블을 생성합니다 :

____________________
|  USER_ID| POST_ID |
|_________|_________|
|         |         |
|_________|_________|

1
질문 :이 추가 테이블이 이미 있으면 어떻게합니까? JoinTable은 존재하는 것을 무시하지 않습니까?
TheWandererr

@TheWandererr 질문에 대한 답변을 찾았습니까? 나는 이미 조인 테이블을 가지고있다
11

필자의 경우 소유 사이드 테이블에 중복 열을 만들고 있습니다. 예를 들어. POST의 POST_ID 왜 그런 일이 일어나고 있는지 제안 할 수 있습니까?
SPS

0

@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있으며 , 우리의 경우에는 레코드가 아닌 다른 부모 레코드에 대해 DELETE 문이 발행 MERGE되므로 계단식 REMOVE은 잘못된 생각 이기 때문에 설정됩니다 . 이 주제에 대한 자세한 내용은 이 기사를 확인 하십시오 .tagpost_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
}

Hibernate는 위의 엔티티 매핑을 위해 다음과 같은 데이터베이스 스키마를 가정 할 것이다 :

단방향 <code> @OneToMany </ code> JPA 연관 데이터베이스 테이블

이미 설명한 것처럼 단방향 @OneToManyJPA 매핑은 다 대다 연결처럼 동작합니다.

링크 테이블을 사용자 정의하기 위해 @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측면 만 사용하는 것이 좋습니다 . 이 주제에 대한 자세한 내용은 이 기사 를 확인하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.