객체의 상속 구조와 데이터베이스의 슈퍼타입 서브타입 관계를 매핑하는 것
슈퍼타입 서브타입(논리 모델)을 테이블(물리 모델)로 구현하는 방법에 대해 알아보자.
엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본 키를 받아서 기본키 + 외래키로 사용하는 전략이다.
💡테이블은 타입의 개념이 없기 때문에 타입을 구분하는 칼럼을 추가해야 한다.
다음은 조인 전략을 사용한 코드이다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED) // 상속 매핑, 조인 전략 사용
@DiscriminatorColumn(name = "DTYPE") // DTYPE 칼럼을 구분 칼럼으로 사용
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("B") // 구분 칼럼에 값 B가 저장
@PrimaryKeyJoinColumn(name = "BOOK_ID") // 기본키 칼럼명을 BOOK_ID로 변경
public class Book extends Item{
private String author;
private String isbn;
}
관련 어노테이션
조인 전략의 장점
조인 전략의 단점
테이블을 하나만 사용해서 통합한다.
💡자식 엔티티가 매핑한 칼럼은 모두 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 int price;
}
단일 테이블 전략의 장점
단일 테이블 전략의 단점
서브 타입마다 하나의 테이블을 만든다.
@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;
}
구현 클래스마다 테이블 전략의 장점
구현 클래스마다 테이블 전략의 단점
부모 클래스는 테이블과 매핑하지 않고, 부모 클래스를 상속 받는 자식 클래스에게 매핑 정보만 제공하고 싶을 때 사용한다.
즉 실제 테이블과 매핑되지 않으며, 단순히 매핑 정보를 상속할 목적으로만 사용된다.
@MappedSuperclass // 주로 사용하는 공통 매핑 정보를 정의
public abstract class BaseEntity{
@Id @GeneratedValue
private Long id;
private String name;
}
@Entity
public class Memeber extends BaseEntity{ // 매핑 정보를 상속받음
private String email;
}
💡@AttributeOverrides, @AttributeOverride : 매핑 정보를 재정의
@AssociationOverrides, @AssociationOverride : 연관관계를 재정의
식별 관계와 비식별 관계는 외래 키가 기본 키에 포함되는지 여부에 따라 구분한다.
두 관계에 대해 알아보자.
식별 관계
부모 테이블의 기본키를 내려받아서 자식 테이블의 기본키 + 외래키로 사용한다.
비식별 관계
부모 테이블의 기본키를 받아서 자식 테이블의 외래키로만 사용한다.
비식별 관계는 외래키에 NULL을 허용하는지에 따라 구분한다.
1. 필수적 비식별 관계 : 외래키에 NULL을 허용하지 않는다.
2. 선택적 비식별 관계 : 외래키에 NULLL을 허용한다.
다음은 복합키를 지원하기 위한 두가지 방법이다.
@IdClass
@Entity
@IdClass(ParentId.class) // ParentId 클래스를 식별자 클래스로 지정
public class Parent{
@Id
@Column(name = "PARENT_ID1")
private String id1;
}
@EmbeddedId
@Entity
public class Parent{
@EmbeddedId
private ParentId id;
private String name;
}
equals(), hashCode()
식별 관계에서 자식 테이블은 부모 테이블의 기본 키를 포함해서 복합 키를 구성해야 하므로 @IdClass나 @EmbeddedId를 사용해서 식별자를 매핑해야 한다.
@IdClass
@EmbeddedId
식별 관계
비식별 관계
💡위와 같은 특징들로 식별 관계보다 비식별 관계를 선호한다.
조인 칼럼 사용
조인 테이블 사용
일대일 조인 테이블
일대다 조인 테이블
다대다 조인 테이블
💡조인 테이블에 칼럼을 추가하면 @JoinTable 전략을 사용할 수 없다. 새로운 엔티티를 만들어서 조인 테이블과 매핑해야 한다.
@SecondaryTable을 사용하여 한 엔티티에 여러 테이블을 매핑할 수 있다. 다음은 이 어노테이션을 사용한 예제이다.
@Entity
@Table(name = "BOARD") // BOARD 테이블과 매핑
@SecondaryTable(name = "BOARD_DETAIL", pkJoinColumns = @PrimaryKeyJoinColmn(name = "BOARD_DETAIL_ID")) // BOARD_DETAIL 테이블을 추가로 매핑
public class Board{
@Id @GeneratedValue
@Column(name = "BOARD_ID")
private Long id;
private String title;
@Column(table = "BOARD_DETAIL")
private String content;
}
상속 관계 매핑
@MappedSuperclass
조인 테이블