조인테이블 전략
- 부모가 될 엔티티에 @Inheritance(strategy = InheritanceType.JOINED)를 붙인다.
- 부모 엔티티와 자식 엔티티 각각 생성된다. 부모 엔티티에는 부모가 가진 컬럼에 대해서만 가지고 있고 자식 엔티티에는 자식이 가진 컬럼에 대해서만 값을 가진다. 이 때 자식 엔티티에는 부모 엔티티의 기본키를 기본키겸 외래키로 가지고 있어 join 연산을 할 수 있다.
@Entity
@Builder
@AllArgsConstructor
@Inheritance(strategy = InheritanceType.JOINED)
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int price;
private int stockQuantity;
}
@Entity
@Builder
@AllArgsConstructor
public class Food extends Item{
String chef;
}
void test(){
Food food = Food.builder().price(1).stockQuantity(1).chef("hi").build();
save(food); //repository 생략
}
- Food가 Item에 대해 필드를 가지고 있으므로, Food 객체를 만들고 Item에 있는 필드 데이터까지 모두 넣고 Food에 대해 save() 메소드를 호출하면 Item과 Food 각각 insert 해준다.
- Food를 조회할 때는 Item을 무조건 조인시켜서 조회한다.
싱글테이블 전략
- 부모가 될 엔티티에 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)와 @DiscriminatorColumn(name="DTYPE")를 붙인다. 자식 엔티티에는 @DiscriminatorValue("VALUE")를 붙인다.
- 자식 엔티티와 부모엔티티가 함께 있는 엔티티가 생성되고 부모 엔티티의 테이블 명을 따른다. 이 때 DTYPE이라는 컬럼이 생기는데 아래의 예제의 경우 FOOD라는 값이 들어간다. 즉 @ DiscriminatorColumn은 어떤 자식 엔티티인지 구분해주는 역할을 해준다.
- 조인테이블 전략보다 실무에서 많이 쓴다. 조인테이블 전략은 자식 엔티티 생성 시 부모와 자식 엔티티를 따로 insert해야하고, join연산도 이뤄져야 하기 때문이다.
@Entity
@Builder
@AllArgsConstructor
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DTYPE")
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int price;
private int stockQuantity;
}
@Entity
@Builder
@AllArgsConstructor
@DiscriminatorValue("FOOD")
public class Food extends Item{
String chef;
}
void test(){
Food food = Food.builder().price(1).stockQuantity(1).chef("hi").build();
save(food); //repository 생략
}
- @DiscriminatorColumn에 name 값을 바꾸면 테이블에서 지정한 name 값을 가진 컬럼명이 된다.
- 만약 Food 외에 Product가 있을 때, Food와 관련된 컬럼은 모두 null 값으로 들어간다.
- 따라서 nullable이어야 하며, 원시 타입이면 안 된다.
- 하위 클래스에 대해 조회할 때는 하위 클래스가 가지고 있는 DTYPE value에 대한 where 조건이 무조건 추가되어 이루어진다.
@MappedSuperclass
@MappedSuperclass
public abstract class BaseEntity {
private String createdBy;
private LocalDateTime createdAt;
}
@Entity
public class Item extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String description;
}
- BaseEntity는 엔티티는 아니고, 그저 중복 방지를 위한 컬럼을 모아놓는 클래스라고 보면 된다.
- 꼭 @MappedSuperclass 어노테이션을 붙여줘야 한다.
- 직접 생성해서 사용할 일이 없으므로 abstract 키워드를 붙이는 것을 권장한다.