카테고리 없음
[JPA]상속관계맵핑
노트코드
2022. 1. 21. 02:02
조인전략

@Entity
@Inheritance(strategy=InheritanceType.JOINED) // join 전략을 사용
@DiscriminatorColumn(name = "DTYPE") // 부모 클래스에 구분 컬럼을 지정
public class Item{
@Id @GenerateValue
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue(value = "A")
public class Album extends Item{
private String artist;
}
@Entity
@DiscriminatorValue(value = "M")
public class Movie extends Item{
private String director;
private String actor;
}
@Entity
@DiscriminatorValue(value = "B")
@PrimaryKeyJoinColumn(name = "BOOK_ID")
public class Book extends Item{
private String author
private String isbn;
}
@Inheritance(strategy=InheritanceType.JOINED)
상속 매핑은 부모 클래스에 @Inheritance를 사용, 그리고 매핑 전략 설정@DiscriminatorColumn(name = "DTYPE")
부모 클래스에 구분 컬럼을 지정, 이 컬럼으로 지정된 자식 테이블을 구분할 수 있다.@DiscriminatorValue(value = "A")
엔티티를 저장할 때 구분 컬럼에 입력할 값을 지정한다.

- @PrimaryKeyJoinColumn(name = "BOOK_ID")
Book 테이블의 ITEM_ID 기본 키 컬럼명을 BOOK_ID로 변경

이런 구조에서 데이터를 넣게되면 ITEM와 MOIVE테이블에 맞는 데이터가 들어가게 되고,데이터조회할때는 PK이자 FK인 ID로 join해서 가져오게된다.
장점
- 테이블 정규화
- 외래 키 참조 무결성 제약조건 활용가능
- 저장공간 효율화
단점
- 조회시 조인을 많이 사용, 성능 저하
- 조회 쿼리가 복잡함
- 데이터 저장시 Insert SQL 2번 호출
특징
- JPA 표준 명세는 구분 컬럼을 사용하도록 하지만 하이버네이트를 포함한 몇몇 구현체는 구분 컬럼 없이도 동작한다.
단일 테이블 전략
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@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 int price;
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
}
@Entity
@DiscriminatorValue("B")
public class Book extends Item {
}

위의 코드를 실행하였을경우 위의 이미지 처럼 테이블이 생성됨, 즉 모든 필드가 한 테이블로 들어옴
장점
- 쿼리할때 join이 발생하지 않는다.
- 조회 쿼리가 단순함
단점
- NULL을 허용해야함
- 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수있음, 상황에 따라서 조회 성능이 오히려 느려질 수 있다.
특징
- 구분 컬럼을 꼭 사용해야 한다. 따라서 @DiscriminatorColumn을 꼭 설정해야 한다.
- @DiscriminatorValue를 지정하지 않으면 기본으로 엔티티 이름을 사용한다.
(Movie, Album, Book)
구현 클래스마다 테이블 전략
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class ItemTablePerClass {
@Id
@GeneratedValue
@Column
private Long id;
private String name;
private int price;
}
@Entity
public class MovieTablePerClass extends ItemTablePerClass {
}
@Entity
public class BookTablePerClass extends ItemTablePerClass {
}
@Entity
public class AlbumTablePerClass extends ItemTablePerClass {
}

위 방식으로 만들면 ITEM테이블은 생성되지 않는다. 하지만 ITEM을 상속받은 각각의 테이블에는
위 그림처럼 해당 테이블에 필요한 컬럼이 전부 들어간다.
단점
- 내가 찾고자 하는 데이터가 어느 테이블에 있는지 몰라서 모든 테이블을 전부 조회해서 union해야함
- 새로운 타입이 추가될때 테이블을 너무 많이 수정 해야함
특징
- 구분 컬럼을 사용하지 않는다.
@MappedSuperClass
부모 클래스는 테이블과 매핑하지 않고, 부모 클래스를 상속받는 자식 클래스에게 매핑 정보만 제공하고 싶을때 @MappedSuperClass를 사용하면된다

@MappedSuperclass
public class BaseEntity {
@Id
@GeneratedValue
private Long id;
private String name;
}
@Entity
public class Member extends BaseEntity {
private String email;
}
@Entity
public class Seller extends BaseEntity {
private String shopName;
}
실행결과 Member 와 Seller 테이블에 Id와 name이 들어있는것을 확인할 수 있다.
또한 BaseEntity 테이블은 생성이 되지 않는다.

부모로 부터 물려받은 매핑 정보 재정의 하기
// 한개일때
@Entity
@AttributeOverride(name = "id", column = @Column(name = "MEMBER_ID"))
public class Member extends BaseEntity {
private String email;
}
//2개이상일때
@Entity
@AttributeOverrides({@AttributeOverride(name = "id", column = @Column(name = "SELLER_ID")),
@AttributeOverride(name = "name", column = @Column(name = "SELLER_NAME"))
})
public class Seller extends BaseEntity {
private String shopName;
}
특징
- 테이블과 매핑되지 않고 자식 클래스에 엔티티의 매핑 정보를 상속하기 위해 사용한다.
- @MappedSuperclass로 지정한 클래스는 엔티티가 아니므로 em.find()나 JPQL에서 사용 불가
- 이 클래스를 직접 생성해서 사용할 일은 거의 없으므로 추상 클래스로 만드는 것을 권장