꿈꾸는 새벽하늘

06장. 다양한 연관관계 매핑 본문

🌿 Spring & Spring Boot/📗 자바 ORM 표준 JPA 프로그래밍

06장. 다양한 연관관계 매핑

rovemin 2023. 7. 3. 23:25

엔티티의 연관관계 매핑 시 고려사항

  • 다중성: 다대일, 일대다, 일대일, 다대다
  • 단방향, 양방향
  • 연관관계의 주인

1. 다대일

다대일 관계의 반대 방향은 일대다 관계이고, 일대다 관계의 반대 방향은 항상 다대일 관계이다.

일(1), 다(N) 관계에서 외래 키는 다(N)쪽에 있으므로 객체 양방향 관계에서 연관관계의 주인은 항상 다쪽이다.

1) 다대일 단방향 [N:1]

회원은 Member.team으로 팀 엔티티를 참조할 수 있지만, 팀은 회원을 참조하는 필드가 없는 연관관계

// == 회원 엔티티 == //
@ManyToOne
@JoinColumn (name = "TEAM_ID")	// Member.team 필드를 TEAM_ID 외래 키와 매핑
private Team team;

2) 다대일 양방향 [N:1, 1:N]

  • 양방향 연관관계는 외래 키가 있는 쪽이 연관관계의 주인이다.
  • 양방향 연관관계는 항상 서로를 참조해야 한다.
// == 회원 엔티티 == //
@ManyToOne
@JoinColumn (name = "TEAM_ID")	// Member.team 필드를 TEAM_ID 외래 키와 매핑
private Team team;

// == 팀 엔티티 == //
@OneToMany (mappedBy = "team")
private List<Member> members = new ArrayList<Member>();

2. 일대다

1) 일대다 단방향 [1:N]

팀은 회원들을 참조하지만 회원은 팀을 참조하지 않는 연관관계

// == 팀 엔티티 == //
@OneToMany
@JoinColumn (name = "TEAM_ID")	// 회원 테이블의 TEAM_ID (FK)
private List<Member> members = new ArrayList<Member>();

일대다 단방향 매핑을 사용하면 엔티티를 매핑한 테이블이 아닌 다른 테이블의 외래 키를 관리해야 한다.

따라서 일대다 단방향 매핑보다는 다대일 양방향 매핑이 권장된다.

2) 일대다 양방향 [1:N, N:1]

일대다 단방향 매핑 반대편에 다대일 단방향 매핑을 추가하여 일대다 양방향 매핑을 할 수 있다.

TEAM_ID 외래 키 컬럼 매핑으로 인해 둘 다 같은 키를 관리하게 되어 문제가 생길 수 있으므로 반대편인 다대일 쪽은 읽기만 가능하게 설정해야 한다.

// == 팀 엔티티 == //
@OneToMany
@JoinColumn (name = "TEAM_ID")	// 회원 테이블의 TEAM_ID (FK)
private List<Member> members = new ArrayList<Member>();

// == 회원 엔티티 == //
@ManyToOne
@JoinColumn (name = "TEAM_ID", insertable = false, updatable = false)
private Team team;

이 방법은 일대다 단방향 매핑 반대편에 다대일 단방향 매핑을 읽기 전용으로 추가해서 일대다 양방향처럼 보이도록 하는 방법이어서 일대다 단방향 매핑의 단점을 그대로 가진다.

따라서 다대일 양방향 매핑이 권장된다.

3. 일대일 [1:1]

  • 일대일 관계는 그 반대도 일대일 관계이다.
  • 일대일 관계는 주 테이블이나 대상 테이블 중 어느 곳이나 외래 키를 가질 수 있다.

1) 주 테이블에 외래 키

주 테이블에 외래 키를 두고 대상 테이블을 참조하는 방식으로, 외래 키를 객체 참조와 비슷하게 사용할 수 있다.

주 테이블이 외래 키를 가지고 있으므로 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.

양방향인 경우 mappedBy 선언을 통해 연관관계의 주인이 아님을 설정해야 한다.

2) 대상 테이블에 외래 키

대상 테이블에 외래 키를 두는 방식으로, 테이블 관계를 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지할 수 있다.

4. 다대다 [N:N]

1) 다대다 단방향

// == 회원 엔티티 (상대 엔티티는 상품 엔티티) == //
@ManyToMany
@JoinTable (name = "MEMBER_PRODUCT", 
           joinColumns = @JoinColumn (name = "MEMBER_ID"),
           inverseJoinColumns = @JoinColumn (name = "PRODUCT_ID"))
private List<Product> products = new ArrayList<Product>();
  • @JoinTable.name: 연결 테이블 지정
  • @JoinTable.joinColumns: 현재 방향인 엔티티와 매핑할 조인 컬럼 정보 지정
  • @JoinTable.inverseJoinColumns: 반대 방향인 엔티티와 매핑할 조인 컬럼 정보 지정

2) 다대다 양방향

// == 회원 엔티티 == //
@ManyToMany
@JoinTable (name = "MEMBER_PRODUCT", 
           joinColumns = @JoinColumn (name = "MEMBER_ID"),
           inverseJoinColumns = @JoinColumn (name = "PRODUCT_ID"))
private List<Product> products = new ArrayList<Product>();

// == 상품 엔티티 == //
@ManyToMany (mappedBy = "products")	// 역방향 추가
private List<Member> members;

3) 다대다 연관관계

다대다 관계를 일대다 다대일 관계로 풀어내기 위해 연결 테이블을 만들 때 식별자 구성 방식

  • 식별 관계: 받아온 식별자를 기본 키 + 외래 키로 사용
  • 비식별 관계: 받아온 식별자는 외래 키로만 사용하고 새로운 식별자 추가

비식별 관계를 사용할 경우 복합 키를 위한 식별자 클래스를 만들지 않아도 되어 단순하고 편리한 ORM 매핑이 가능해진다.