꿈꾸는 새벽하늘

07장. 고급 매핑 본문

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

07장. 고급 매핑

rovemin 2023. 7. 11. 00:02

1. 상속 관계 매핑

관계형 데이터베이스에는 객체지향 언어에서 다루는 상속의 개념이 없지만 슈퍼타입 서브타입 관계 기법으로 모델링하면 상속 관계와 유사하게 매핑할 수 있다. 슈퍼타입 서브타입 논리 모델을 테이블로 구현할 때 3가지 방법을 선택할 수 있다.

  • 각각의 테이블로 변환: 각각을 모두 테이블로 만들고 조회할 때 조인을 사용한다. JPA에서는 조인 전략이라 한다.
  • 통합 테이블로 변환: 테이블을 하나만 사용해서 통합한다. JPA에서는 단일 테이블 전략이라 한다.
  • 서브타입 테이블로 변환: 서브 타입마다 하나의 테이블을 만든다. JPA에서는 구현 클래스마다 테이블 전략이라 한다.

조인 전략 (Joined Strategy)

조인 전략은 엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본 키를 받아서 기본 키 + 외래 키로 사용하는 전략이다.

테이블은 타입의 개념이 없기 때문에 이 전략을 사용할 시 타입을 구분하는 컬럼을 추가해야 한다.

 

JPA 표준 명세는 구분 컬럼을 사용하도록 하지만 하이버네이트를 포함한 몇몇 구현체는 구분 컬럼(@DiscriminatorColumn) 없이도 동작한다.

단일 테이블 전략 (Single-Table Strategy)

단일 테이블 전략은 테이블을 하나만 사용하고 구분 컬럼(DTYPE)으로 저장된 자식 테이블을 구분한다.

 

구분 컬럼을 반드시 사용해야 하므로 @DiscriminatorColumn을 꼭 설정해야 한다.

@DiscriminatorValue를 지정하지 않으면 기본으로 엔티티 이름을 사용한다.

구현 클래스마다 테이블 전략 (Table-per-Concrete-Class Strategy)

구현 클래스마다 테이블 전략은 자식 엔티티마다 테이블을 만들고 자식 테이블 각각에 필요한 컬럼이 모두 있다.

 

이 전략은 구분 컬럼을 사용하지 않는다.

자식 엔티티마다 테이블을 만드는 방식이므로 일반적으로 추천하지 않는 전략이다.

2. @MappedSuperclass

@MappedSuperclass는 부모 클래스를 테이블과 매핑하지 않고 부모 클래스를 상속받는 자식 클래스에게 매핑 정보만 제공하기 위해 사용한다.

즉, 실제 테이블과 매핑되지 않고 자식 클래스에 엔티티의 매핑 정보를 상속할 목적으로 사용된다.

 

@MappedSuperclass로 지정한 클래스는 엔티티가 아니므로 em.find()나 JPQL에서 사용할 수 없다.

이 어노테이션을 사용하면 등록일자, 수정일자, 등록자, 수정자 등 여러 엔티티에서 공통으로 사용하는 속성을 효과적으로 관리할 수 있다.

3. 복합 키와 식별 관계 매핑

1) 식별 관계 vs 비식별 관계

  • 식별 관계: 부모 테이블의 기본 키를 내려받아서 자식 테이블의 기본 키 + 외래 키로 사용하는 관계
  • 비식별 관계: 부모 테이블의 기본 키를 받아서 자식 테이블의 외래 키로만 사용하는 관계

 

비식별 관계는 외래 키에 NULL을 허용하는지에 따라 필수적 비식별 관계와 선택적 비식별 관계로 나눈다.

  • 필수적 비식별 관계: 외래 키에 NULL을 허용하지 않아서 연관관계를 필수적으로 맺어야 한다.
  • 선택적 비식별 관계: 외래 키에 NULL을 허용하며 연관관계를 선택적으로 맺을 수 있다.

2) 복합 키

JPA는 복합 키를 지원하기 위해 2가지 방법을 제공한다. 이 중 @IdClass는 관계형 데이터베이스에 가까운 방법이고 @EmbeddedId는 보다 객체지향에 가까운 방법이다.

@IdClass

@IdClass를 사용하기 위해서는 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 같아야 하고 식별자 클래스가 public이어야 한다.

그리고 Serializable 인터페이스와 equals, hashCode를 구현해야 하며 생성자가 있어야 한다. 

@EmbeddedId

@EmbeddedId를 적용한 식별자 클래스는 식별자 클래스에 기본 키를 직접 매핑한다.

또한, @Embeddable 어노테이션 선언, Serializable 인터페이스 구현, equals와 hashCode 구현, 기본 생성자 존재, public인 식별자 클래스의 조건들이 모두 만족되어야 한다.

3) 비식별 관계로 구현

비식별 관계로 구현할 경우 식별 관계의 복합 키를 사용한 코드보다 매핑도 쉽고 코드도 단순하다.

그리고 복합 키가 없으므로 복합 키 클래스를 만들지 않아도 된다.

4) 일대일 식별 관계

일대일 식별 관계는 자식 테이블의 기본 키 값으로 부모 테이블의 기본 키 값만 사용한다.

그래서 부모 테이블의 기본 키가 복합 키가 아니라면 자식 테이블의 기본 키는 복합 키로 구성하지 않아도 된다.

4. 조인 테이블

데이터베이스 테이블의 연관관계는 조인 컬럼 사용과 조인 테이블 사용의 두 가지 방법으로 설계할 수 있다.

  • 조인 컬럼 사용: 조인 컬럼이라 불리는 외래 키 컬럼을 사용해서 테이블 간 관계를 관리
  • 조인 테이블 사용: 조인 테이블이라는 별도의 테이블을 사용해서 연관관계 관리
    • 객체와 테이블을 매핑할 때 조인 컬럼은 @JoinColumn으로 매핑하고 조인 테이블은 @JoinTable로 매핑한다.
    • 조인 테이블은 주로 다대다 관계를 일대다, 다대일 관계로 풀어내기 위해 사용하지만, 일대일, 일대다, 다대일 관계에서도 사용한다.

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

@SecondaryTable을 사용하면 한 엔티티에 여러 테이블을 매핑할 수 있다.

  • @SecondaryTable.name : 매핑할 다른 테이블의 이름
  • @SecondaryTable.pkJoinColumns : 매핑할 다른 테이블의 기본 키 컬럼 속성