7. 고급 매핑
고급 매핑
- 상속 관계 매핑
- 객체의 상속 관계를 데이터베이스에 어떻게 매핑하는지
- @MappedSuperclass
- 등록일, 수정일 같이 여러 엔티티에서 공통으로 사용하는 매핑 정보만 상속받고 싶을 때 사용
- 복합 키와 식별 관계 매핑
- 데이터베이스의 식별자가 하나 이상일 때 매핑하는 방법
- 데이터베이스 설계에서 이야기하는 식별, 비식별 관계에 대해서
- 조인 테이블
- 테이블을 외래키 하나로 연관관계 맺는 것이 아닌 연결 테이블을 이용해서 매핑하는 방법
- 엔티티 하나에 여러 테이블 매핑하기
- 엔티티 하나에 여러 테이블을 매핑하는 방법
1. 상속 관계 매핑
- ORM에서 이야기하는 상속 매핑에 가장 적합한 매핑 방법
- 데이터베이스에는 객체지향의 상속이란 개념이 없음
- 대신 아래 왼쪽 그림처럼 슈퍼타입-서브타입 관계가 존재, 오른쪽은 객체의 상속 관계
- 슈퍼타입-서브타입 논리 모델을 테이블로 구현할 때?
- 각각의 테이블로 변환 : 조인 전략
- 통합 테이블로 변환 : 단일 테이블 전략
- 서브타입 테이블로 변환 : 구현 클래스마다 테이블 전략
1.1 조인 전략 : 각각의 테이블로 변환
- 부모, 자식 엔티티를 각각 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본키를 받아서 기본키 + 외래키로 사용하는 전략
- 객체는 타입으로 구분이 가능하지만 테이블은 타입이란 개념이 없음
- DTYPE 컬럼을 추가해서 구분 컬럼으로 사용해야 함
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
...
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
...
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
private String director;
private String actor;
...
}
- 매핑 정보들
@Inheritance(strategy = InheritanceType.JOINED
- 상속 매핑 시 부모 클래스에 이 어노테이션을 사용해줘야 함
- 조인 전략을 사용하므로
InheritanceType.JOINED
@DiscriminatorColumn(name = "DTYPE")
- 부모 클래스에스 구분 컬럼을 지정
- 이 값으로 자식 테이블 구분 가능
- 기본값이 DTYPE 이므로 name 부분은 생략 가능
@DiscriminatorValue("M")
- 엔티티를 저장할 때 구분 컬럼에 입력할 값을 지정
- 구분 컬럼인 DTYPE에 M 값이 저장됨
- 기본 값으로 부모 테이블의 ID 컬럼명을 바꾸고 싶을 때
@PrimaryKeyJoinColumn
사용@Entity @DiscriminatorValue("B") @PrimaryKeyJoinColumn(name = "BOOK_ID") // ID 재정의 public class Book extends Item { ... }
- 조인 전략의 장단점
- 장점
- 테이블이 정규화 됨
- 외래키 참조 무결성 제약조건을 활용할 수 있음
- 저장공간을 효율적으로 사용
- 단점
- 조회할 때 조인이 많이 사용되므로 성능 저하가 가능
- 조회 쿼리가 복잡함
- 데이터를 등록할 때 INSERT SQL이 두 번 실행됨
- 장점
- 특징
- JPA 표준 명세는 구분 컬럼을 사용하도록 하지만 하이버네이트를 포함한 몇몇의 구현체에서는 구분 컬럼(@DiscriminatorColumn) 없이도 동작
- 관련 어노테이션
- @PrimaryKeyJoinColumn, @DiscriminatorColumn, @DiscriminatorValue
1.2 단일 테이블 전략 : 통합 테이블로 변환
- 테이블을 하나만 사용하고 DTYPE 컬럼으로 어떤 자식 데이터인지 구분(구분 컬럼 필수)
- 조인을 사용하지 않으므로 일반적으로 가장 빠름
- 자식 엔티티가 매핑한 컬럼들이 모두 null을 허용해야 함
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private String price;
...
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item { ... }
@Entity
@DiscriminatorValue("M")
public class Movie extends Item { ... }
- 단일 테이블 전략의 장단점
- 장점
- 조인이 필요 없으므로 일반적으로 조회 성능이 빠름
- 조회 쿼리가 단순함
- 단점
- 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 함
- 테이블이 커질 수 있으므로 조회 성능이 더 느려질 수 있다
- 장점
- 특징
- 구분 컬럼이 필수 (@DiscriminatorColumn)
- 구분 컬럼을 지정하지 않으면 기본으로 엔티티 이름을 사용
1.3 구현 클래스마다 테이블 전략 : 서브타입 테이블로 변환
- 자식 엔티티마다 테이블을 만들고 각각에 필요한 컬럼도 만들어주는 전략
- 일반적으로 추천하지 않는 전략
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class Item { @Id @GeneratedValue @Column(name = "ITEM_ID") private Long id; private String name; private int price; ... } @Entity public class Album extends Item { ... } @Entity public class Movie extends Item { ... }
- 구현 클래스마다 테이블 전략의 장단점
- 장점
- 서브 타입을 구분해서 처리할 때 효과적
- not null 제약조건을 사용할 수 있음
- 단점
- 여러 자식 테이블을 함께 조회할 때 성능이 느림(SQL이 UNION을 사용해야 함)
- 자식 테이블을 통합해서 쿼리하기 어려움
- 장점
- 특징
- 구분 컬럼을 사용하지 않는다
2. @MappedSuperclass
- 부모 클래스는 테이블과 매핑하지 않고 자식 클래스에 매핑 정보만 제공하고 싶을 때 사용
- @Entity는 실제 테이블과 매핑, @MappedSuperclass는 실제 테이블 매핑 X
- 추상 클래스로 설계 권장 - 상속용, 생성해서 사용할 일이 없기 때문
- BaseEntity를 @MappedSuperclass로 선언하고 Member, Seller가 상속받아서 사용
@MappedSuperclass
public abstract class BaseEntity {
@Id @GeneratedValue
private Long id;
private String name;
...
}
@Entity
public class Member extends BaseEntity {
// id, name은 상속받음
private String email;
...
}
@Entity
public class Seller extends BaseEntity {
// id, name은 상속받음
private String shopName;
...
}
- **부모로부터 상속받은 걸 오버라이드 하려면? **
- 매핑 정보를 오버라이드
- @AttributeOverrides, @AttributeOverride
@Entity @AttributeOverride(name = "id", column = @Column(name = "MEMBER_ID")) public class Member extends BaseEntity { ... }
- 연관관계를 오버라이드
- @AssociationOverrides, @AssociationOverride
- 매핑 정보를 오버라이드
- 정리하면?
- 테이블과 매핑되지 않고 자식에게 물려주기 용도로 사용
- @MappedSuperclass로 지정한 클래스는 엔티티가 아니므로 em.find()나 JPQL에서 사용 불가
- 생성해서 사용할 일이 없으므로 추상클래스로 만드는 것이 권장됨
3. 복합 키와 식별 관계 매핑
: 추후 업로드
4. 조인 테이블
: 추후 업로드
5. 엔티티 하나에 여러 테이블 매핑하기
: 추후 업로드