본문 바로가기
STUDY/JPA

고급 매핑 #3 조인 테이블

by Anne of Green Galbes 2020. 2. 3.

이 글은 김영한의 자바 ORM 표준 JPA 프로그래밍을 보고 작성한 글임을 알려드립니다.

관련 강의 : 인프런스 자바 ORM 표준 JPA 프로그래밍 - 기본편


데이터베이스 테이블의 연관관계를 설계하는 방법은

  • 조인 컬럼 사용(외부 키 사용)
  • 조인 테이블 사용(테이블 사용)

이렇게 크게 두 가지가 있다.

 

1) 조인 컬럼 사용

테이블 간에 관계는 주로 조인 컬럼이라 부르는 외래 키 컬럼을 사용해서 관리한다.

회원과 사물함이 있는데 각각 테이블에 데이터를 등록했다가 회원이 일할 때 사물함을 선택할 수 있다고 가정을 하면 회원이 사물함을 사용하기 전까지는 아직 둘 사이의 관계가 없으므로 Member 테이블의 외래 키에 null 값을 입력해 두어야 한다. 이처럼 외래 키에 null 값을 허용하는 관계를 선택적 비식별 관계라 한다.

선택적 비식별 관계는 외래키에 null값을 허용하므로 조인할 때 외부조인(Outer join)을 사용해야 한다.

 

2) 조인 테이블 사용

조인 테이블이라는 별도의 테이블을 사용해서 연관관계를 관리한다. 연관관게를 관리하는 조인 테이블을 추가하고 여기서 두 테이블의 외래 키를 가지고 연관관게를 관리하므로 Member와 Locker에는 연관관계를 관리하기 위한 외래 키 컬럼이 없다.

이 조인 테이블의 가장 큰 단점은 테이블을 하나 추가해야 한다는 것이며, 그로 인해 관리해야 하는 테이블이 늘어나고, 조인을 할 경우 조인 테이블까지 추가로 조인을 해야 한다.

 

그래서 평소에는 조인 컬럼을 사용해서 연관관계를 설계하고 필요에 따라 조인 테이블을 추가한다.

 

참고
  • 조인 컬럼은 @JoinColumn으로 매핑한다.
  • 조인 테이블은 @JoinTable로 매핑한다.
  • 조인 테이블은 주로 다대다 관계를 일대다, 다대일 관계로 풀어내기 위해 사용하지만, 일대일, 일대다, 다대일 관계에서도 사용한다.

 

1. 일대일 조인 테이블

//부모
@Entity
public class Parent {
  @Id
  @GeneratedValue
  @Column(name = "PARENT_ID")
  private Long id;

  private String name;

  @OneToOne
  @JoinTable(name = "PARENT_CHILD",
    joinColumns = @JoinColumn(name = "PARENT_ID"),
    inverseJoinColumns = @JoinColumn(name = "CHILD_ID"))
  private Child child;
}

//자식
@Entity
public class Child {

  @Id
  @GeneratedValue
  @Column(name = "CHILD_ID")
  private Long id;

  private String name;

}

부모 엔티티에서 @JoinColumn이 아닌 @JoinTable을 사용하고 있다. 다음은 @JoinTable의 속성이다.

속성 기능
name 매핑할 조인 테이블 이름
joinColumns 현재 엔티티를 참조하는 외래 키
inverseJoinColumns 반대방향 엔티티를 참조하는 외래 키

 

2. 일대다 조인 테이블

일대다 관계를 만들기 위해서는 다와 관련된 컬럼에 유니크 제약조건을 걸어야 한다.

//부모
@Entity
public class Parent {
  @Id
  @GeneratedValue
  @Column(name = "PARENT_ID")
  private Long id;

  private String name;

  @OneToMany
  @JoinTable(name = "PARENT_CHILD",
    joinColumns = @JoinColumn(name = "PARENT_ID"),
    inverseJoinColumns = @JoinColumn(name = "CHILD_ID"))
  private List<Child> child = new ArrayList<>();
}

//자식
@Entity
public class Child {

  @Id
  @GeneratedValue
  @Column(name = "CHILD_ID")
  private Long id;

  private String name;
}

 

3. 다대일 조인 테이블

다대일은 일대다에서 방향만 반대이므로 일대다 조인 테이블과 모양이 같다.

//부모
@Entity
public class Parent {
  @Id
  @GeneratedValue
  @Column(name = "PARENT_ID")
  private Long id;

  private String name;

  @OneToMany(mappedBy = "parent")
  private List<Child> child = new ArrayList<>();
}

//자식
@Entity
public class Child {

  @Id
  @GeneratedValue
  @Column(name = "CHILD_ID")
  private Long id;

  private String name;

  @ManyToOne(optional = false)
  @JoinTable(name = "PARENT_CHILD",
    joinColumns = @JoinColumn(name = "CHILD_ID"),
    inverseJoinColumns = @JoinColumn(name = "PARENT_ID"))
  private Parent parent;
}

이는 다대일, 일대다 양방향 관계로 매핑한 코드이다.

 

4. 다대다 조인 테이블

다대다 관계를 만들기 위해서는 두 테이블의 기본 키를 합해서 하나의 복합 유니크 제약 조건을 걸어야 한다.

//부모
@Entity
public class Parent {

  @Id
  @GeneratedValue
  @Column(name = "PARENT_ID")
  private Long id;

  private String name;

  @ManyToMany
  @JoinTable(name = "PARENT_CHILD",
    joinColumns = @JoinColumn(name = "PARENT_ID"),
    inverseJoinColumns = @JoinColumn(name = "CHILD_ID"))
  private List<Child> child = new ArrayList<>();

}

//자식
@Entity
public class Child {

  @Id
  @GeneratedValue
  @Column(name = "CHILD_ID")
  private Long id;

  private String name;
}
조인 테이블에 컬럼을 추가하면 @JoinTable 전략을 사용할 수 없다. 대신에 새로운 엔티티를 만들어서 조인 테이블과 매핑해야 한다.

 

5. 엔티티 하나에 여러 테이블 매핑

@Entity
@Data
@Table(name = "BOARD")
@SecondaryTable(name = "BOARD_DETAIL",
pkJoinColumns = @PrimaryKeyJoinColumn(name = "BOARD_DETAIL_ID"))
public class Board {

  @Id
  @GeneratedValue
  @Column(name = "BOARD_ID")
  private Long id;

  private String title;

  @Column(table = "BOARD_DETAIL")
  private String content;
}

위의 코드처럼 @SecondaryTable을 사용하면 한 엔티티에 여러 테이블을 매핑할 수있다.  다음은 @SecondaryTable의 속성이다.

속성 기능
name 매핑할 다른 테이블의 이름
pkJoinColumns 매핑할 다른 테이블의 기본 키 컬럼

더 많은 테이블은 매핑하기 위해서는 @SecondaryTables를 사용하면 된다.

댓글