@Inheritance(strategy = InheritanceType.XXX)
JOINED
: 조인 전략SIGNLE_TABLE
: 단일 테이블 전략TABLE_PER_CLASS
: 구현 클래스마다 테이블 전략@DiscriminatorColumn(name = "DTYPE")
@DiscriminatorValue("XXX")
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public class Item {
@Id
@GeneratedValue
private Long id;
private String name; // 이름
private int price; // 가격
}
@Inheritance(strategy = InheritanceType.JOINED)
@Inheritance
를 사용해야 한다.InheritanceType.JOINED
를 사용했다.@DiscriminatorColumn(name = "DTYPE")
@DiscriminatorColumn
로 줄여 사용할 수 있다.@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
}
@DiscriminatorValue("A")
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
private String director;
private String actor;
}
@Entity
@DiscriminatorValue("B")
public class Book extends Item {
private String author;
private String isbn;
}
CREATE TABLE Item (
id BIGINT NOT NULL,
name VARCHAR(255),
price INTEGER,
DTYPE VARCHAR(31), // 부모(Item)쪽에 DTYPE 생성
PRIMARY KEY (id)
);
CREATE TABLE Album (
artist VARCHAR(255),
id BIGINT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Item (id)
);
CREATE TABLE Movie (
director VARCHAR(255),
actor VARCHAR(255),
id BIGINT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Item (id)
);
CREATE TABLE Book (
author VARCHAR(255),
isbn VARCHAR(255),
id BIGINT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Item (id)
);
// ...
Movie movie = new Movie();
movie.setDreictor("aaa");
movie.setActor("bbb");
movie.setName("바람과함께사라지다");
movie.setPrice(10000);
INSERT INTO Item (neme, price, id) VALUES (?, ?, ?)
INSERT INTO Movie (actor, director id) VALUES (?, ?, ?)
SELECT * FROM item
SELECT * FROM movie
// ...
Movie movie = new Movie();
movie.setDreictor("aaa");
movie.setActor("bbb");
movie.setName("바람과함께사라지다");
movie.setPrice(10000);
em.persist(movie);
em.flush(); // flush, clear을 통해
em.clear(); // 1차 캐시에 아무것도 남지 않는다.
em.find(Movie.class, movie.getId());
System.out.println("fiindMovie = " + findMovie);
SELECT
movie.id as id
item.name as name
item.price as price
movie.actor as actor
movie.director as director
FROM
movie movie
INNER JOIN
Item item
ON item.id = movie.id
WHERE
movie.id = ?
@DiscriminatorColumn
을 반드시 설정해야 한다. 생략 시 기본으로 엔티티이름을 사용한다.@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public class Item {
SINGLE_TABLE
로만 변경하면 끝난다!@DiscriminatorColumn
을 생략해도 DTYPE이 무조건 생긴다.CREATE TABLE Item (
DTYPE VARCHAR(31) not null,
id INT NOT NULL,
name VARCHAR(255),
price INT,
artist VARCHAR(255),
actor VARCHAR(255),
author VARCHAR(255),
isbn VARCHAR(255),
director VARCHAR(255),
PRIMARY KEY (id)
);
INSERT INTO item (name, price, actor, director, DTYPE, id) VALUES(?, ?, ?, ?, 'M', ?)
SELECT
item.id as id
item.name as name
item.price as price
item.actor as actor
item.director as director
FROM
Item item
WHERE
item.id = ?
and item.DTYPE = 'M'
@DiscriminatorColumn
이 적용되지 않는다.@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn
public abstract class Item {
CREATE TABLE Album (
id INT NOT NULL,
name VARCHAR(255),
price INT,
artist VARCHAR(255),
PRIMARY KEY (id)
);
CREATE TABLE Movie (
id INT NOT NULL,
name VARCHAR(255),
price INT,
director VARCHAR(255),
actor VARCHAR(255),
PRIMARY KEY (id)
);
CREATE TABLE Book (
id INT NOT NULL,
name VARCHAR(255),
price INT,
author VARCHAR(255),
isbn VARCHAR(255),
PRIMARY KEY (id)
);
INSERT INTO movie(name, price, actor, director, id) VALUES(?, ?, ?, ?, ?)
SELECT
movie.id as id,
movie.name as name,
movie.price as price,
movie.actor as actor,
movie.director as director
FROM
Movie movie
WHERE
movie.id = ?
📌 결론
- 기본으로 조인 전략을 가져가야 한다.
- 조인 전략의 장단점과 단일 테이블 전략의 장단점을 비교해 트레이드 오프 할 생각으로 고민해보면 된다.
- 영한쌤: 그냥 기본으로 조인 전략 가져가고, 너무 간단해서 일이 없을거 같을때 단일 테이블 전략을 가져간다.
앞서 학습한 상속 관계 매핑은 부모 클래스와 자식 클래스 모두 데이터베이스의 테이블과 매핑했다. 부모클래스는 테이블과 매핑하지 않고 부모 클래스를 상속 받는 자식 클래스에게 매핑 정보만 제공하고 싶으면 @MappedSuperclass
를 사용하면 된다.
@MappedSuperclass
는 비유하자면 추상 클래스와 유사한데 @Entity
는 실제 테이블과 매핑되지만 @MappedSuperclass
는 실제 테이블과는 매핑되지 않는다. 이것은 단순히 매핑 정보를 상속할 목적으로만 사용된다.
@MappedSuperclass
public abstract class BaseEntity {
private String createdBy;
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
}
@Entity
@Getter
@Setter
@Table(name = "member")
public class Member extends BaseEntity {
CREATE TABLE member (
id INT NOT NULL,
createdBy VARCHAR(255),
createdDate TIMESTAMP,
lastModifiedBy VARCHAR(255),
lastModifiedDate TIMESTAMP,
PRIMARY KEY (id)
);
Member member = new Member();
member.setUsername("user");
member.setCreatedBy("kim");
member.setCreatedDate(LocalDateTime.now());
참고
@Entity 클래스는 엔티티나 @MappedSuperclass로 지정한 클래스만 상속할 수 있다.