조인테이블 전략

  • 부모가 될 엔티티에 @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 키워드를 붙이는 것을 권장한다.

+ Recent posts