@Entity
@Inheritance(strategy = InheritanceType.JOINED)
//@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
//@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn
public class Item {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
...getter and setter
}
@Entity
public class Album extends Item{
private String artist;
...getter and setter
}
@Entity
public class Book extends Item{
private String author;
private String isbn;
...getter and setter
}
@Entity
//@DiscriminatorValue("M")
public class Movie extends Item{
private String director;
private String actor;
...getter and setter
}
Movie movie = new Movie();
movie.setDirector("aaa");
movie.setActor("bbb");
movie.setName("바람과 함께 사라지다");
movie.setPrice(10000);
em.persist(movie);
Album album = new Album();
album.setArtist("ccccc");
album.setName("하이요");
album.setPrice(20000);
em.persist(album);
@DiscriminatorColumn
- @DiscriminatorColumn를 적어주면, 부모테이블에 DTYPE컬럼이 생성된다.
- 부모테이블(슈퍼타입)에 DTYPE과 같은 구분할 수 있는 컬럼을 넣어서, 어떤 데이터인지 명시한다.
- DTYPE컬럼의 값은 기본값은 해당 엔티티명이다. 자식데이터(Movie)를 저장하면, 자식엔티티명이 되고, 자식데이터가 아닌 부모데이터(Item) 자체를 저장하면 부모엔티티명이 된다.
- @DiscriminatorColumn는 적어주는것이 좋다. 부모데이터(Item)만 조회하게되면, 해당 데이터가 어떤 데이터를 insert했던것이었는지 구별할수가 없기 때문이다.
- DTYPE컬럼명을 바꾸고 싶으면 @DiscriminatorColumn(name ="DIS_TYPE")과 같이 바꾸면된다.
- DTYPE컬럼의 값을 엔티티명이 아닌 별도로 지정해주고 싶으면, 부모클래스나 자식클래스에서 @DiscriminatorValue("M")이런식으로 지정해주면 된다.

추상클래스
- 참고로 abstract class Item처럼 추상클래스로 지정하면, Item item = new Item(); 처럼 객체를 생성할 수 없다.
- 구현클래스마다테이블전략에서는 부모클래스를 추상클래스로 만들면 부모엔티티에 해당하는 부모테이블은 생성되지않는다. 하지만 조인전략과 단일테이블전략은 부모 클래스를 추상클래스여도 부모엔티티에 해당하는 부모테이블이 생성된다.
기본적으로,
Member member = em.find(Member.class, 1); 를 하면 MEMBER테이블에서만 select하고,
Item item = em.find(Item.class, 1); 을 하면 ITEM테이블에서 select한다.


❓왜 left join을 하거나 inner join을 할까?
select
*
from
ITEM i
left join
Album a
on
a.id = i.id

select
*
from
MOVIE m
inner join
ITEM i
on
i.id = m.id

left join을 하면 on조건절에 해당하지않으면 일단 데이터를 붙이긴하는데 null값이 들어가는거고,
inner join을 하면 on조건절에 해당하지않으면 MOVIE데이터뿐만아니라 ITEM데이터도 조회가 안된다. 즉 inner join은 on조건절에 해당하는 데이터만 조회한다.
참고로, 어떤 전략이든 상관없이 영속성 컨텍스트 조회나 db조회 시 em.find(Item.class, id)를 했는데 Book객체가 리턴되더라도, 이때에는 Item item = em.find(Item.class, id); 처럼 해야한다. em.find()를 할때 반환타입을 Item.class라고 지정했으므로 Book book = em.find(Item.class, id)가 아니라 Item item = em.find(Item.class, id);로 해야한다.


select
item0_.id as id1_2_0_,
item0_.name as name2_2_0_,
item0_.price as price3_2_0_,
item0_.artist as artist1_0_0_,
item0_.author as author1_1_0_,
item0_.isbn as isbn2_1_0_,
item0_.actor as actor1_6_0_,
item0_.director as director2_6_0_,
item0_.clazz_ as clazz_0_
from
(select
id,
name,
price,
null as artist,
null as author,
null as isbn,
null as actor,
null as director,
1 as clazz_
from
Item
union
all select
id,
name,
price,
artist,
null as author,
null as isbn,
null as actor,
null as director,
1 as clazz_
from
Album
union
all select
id,
name,
price,
null as artist,
author,
isbn,
null as actor,
null as director,
2 as clazz_
from
Book
union
all select
id,
name,
price,
null as artist,
null as author,
null as isbn,
actor,
director,
3 as clazz_
from
Movie
) item0_
where
item0_.id=?select
item0_.id as id1_2_0_,
item0_.name as name2_2_0_,
item0_.price as price3_2_0_,
item0_.artist as artist1_0_0_,
item0_.author as author1_1_0_,
item0_.isbn as isbn2_1_0_,
item0_.actor as actor1_6_0_,
item0_.director as director2_6_0_,
item0_.clazz_ as clazz_0_
from
( select
id,
name,
price,
artist,
null as author,
null as isbn,
null as actor,
null as director,
1 as clazz_
from
Album
union
all select
id,
name,
price,
null as artist,
author,
isbn,
null as actor,
null as director,
2 as clazz_
from
Book
union
all select
id,
name,
price,
null as artist,
null as author,
null as isbn,
actor,
director,
3 as clazz_
from
Movie
) item0_
where
item0_.id=?UNION ALL
select id, name, price, artist, null as author, null as isbn, null as actor, null as director, 1 as clazz_ from Album union all select id, name, price, null as artist, null as author, null as isbn, actor, director, 3 as clazz_ from Movie
- UNION ALL은 두 개 이상의 SELECT 결과를 행 단위로 결합한다.
select
movie0_.id as id1_2_0_,
movie0_.name as name2_2_0_,
movie0_.price as price3_2_0_,
movie0_.actor as actor1_6_0_,
movie0_.director as director2_6_0_
from
Movie movie0_
where
movie0_.id=?@MappedSuperclass
public abstract class BaseEntity { // ✅상속 가능
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class BaseEntity { // ✅상속 가능
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}public class BaseEntity { // ❌상속 불가능
private Long id;
}@Entity
public class User extends BaseEntity { // ✅상속
private String name;
}