JPA 고급 매핑
상속 관계 매핑
RDB에는 객체지향 언어에서 다루는 상속 개념이 존재하지 않는다. 그나마 슈퍼타입, 서브타입 관계라는 모델링 기법이 객체의 상속 개념과 가장 유사하다.
조인 전략
- 엔티티 각각을 모두 테이블로 생성하고, 자식 테이블이 부모 테이블의 기본키를 받아 기본키 + 외래키로 사용하는 전략이다.
- 테이블은 타입의 개념이 없어 타입을 구분하는 컬럼을 추가한다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@GeneratedValue @Id
private Long id;
...
}
@Entity
@DiscriminatorValue("A")
@PrimaryKeyJoinColumn(name = "ALBUM_ID")
public class Album extends Item {
private String artist;
...
}
애너테이션 | 선언위치 | 설명 | 기본값 |
---|---|---|---|
@Inheritance(strategy=InheritanceType.XXX) |
부모 | 상속 매핑 전략을 지정한다. 속성값에는 JOINED , SINGLE_TABLE , TABLE_PER_CLASS 이 있다. |
SINGLE_TABLE |
@DiscriminatorColumn(name="XXX") |
부모 | 구분 컬럼을 지정한다. 이 컬럼을 통해 저장된 자식 테이블을 구분한다. 하이버네이트의 조인 전략에서는 @DiscriminatorColumn 을 선언하지 않으면 DTYPE 컬럼이 생성되지 않는다. |
DTYPE |
@DiscriminatorValue("XXX") |
자식 | 엔티티를 저장할 때 슈퍼타입의 구분 컬럼에 저장할 값을 지정한다. | 클래스명 |
@PrimaryKeyJoinColumn(name = "XXX") |
자식 | 상속 매핑에서 자식 테이블의 기본키 컬럼명을 변경할 때 사용한다. | 부모 테이블의 ID 컬럼명 |
조인 전략의 장점
- 테이블이 정규화 됨.
- 외래키 참조 무결성 제약조건을 활용.
- 저장공간을 효율적으로 사용.
조인 전략의 단점
- 조회시 조인을 많이 사용하므로 성능 저하.
- 조회 쿼리가 복잡해짐.
- 데이터 저장시 INSERT SQL을 2번 호출.
단일 테이블 전략
테이블을 하나만 사용하여 구분 컬럼(DTYPE)으로 자식 데이터를 구분한다. 그래서 엔티티에 따라 사용하는 컬럼이 다르다.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
...
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
...
}
...
단일 테이블 전략의 장점
- 조인이 필요 없어 조회 성능이 빠름.
- 조회 쿼리가 단순함.
단일 테이블 전략의 단점
- 자식 엔티티가 매핑한 컬럼은 모두 null이 허용됨.
- 단일 테이블에 모두 저장하기 때문에 테이블이 커질 수 있음. 그래서 상황에 따라 조회 성능이 느려짐.
구현 클래스마다 테이블 전략
자식 엔티티마다 테이블을 생성한다. 이 전략은 사용을 지양한다.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
...
}
@Entity
public class Album extends Item {
...
}
...
구현 클래스마다 테이블 전략의 장점
- 서브 타입을 명확하게 구분해서 처리할 때 효과적임.
- not null 제약조건 사용 가능.
구현 클래스마다 테이블 전략의 단점
- 여러 자식 테이블을 함께 조회할 때 성능이 느림.(UNION SQL 필요)
- 자식 테이블을 통합하기 어려움.
@MappedSuperclass
- 테이블과 매핑하지 않고 부모 클래스를 상속받는 자식 클래스에게 매핑 정보만 제공한다.
- 추상 클래스와 비슷하며 실제 테이블과 매핑되지 않는다.
@MappedSuperclass
를 선언한 클래스는 엔티티가 아니므로 조회, 검색이 불가능 하다. 즉,em.find()
, JPQL을 사용할 수 없다.- 직접 생성해서 사용할 일이 없으므로 추상 클래스로 구현하는 것을 권장한다.
- 일반적으로 공통 매핑 정보가 필요할 때 사용된다. (등록일자, 등록자 등)
@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
@AttibuteOverrides({
@AttibuteOverride(name = "id", column = @Column(name = "MEMBER_ID")),
@AttibuteOverride(name = "name", column = @Column(name = "MEMBER_NAME")),
})
public class Member extends BaseEntity {
...
}
엔티티는
@Entity
또는@MappedSuperclass
가 선언된 클래스만 상속 받을 수 있다.
Comments