상속관계 매핑
관계형 데이터베이스는 상속관계가 없다. 대신 슈퍼타입 서브타입 관계라는 모델링 기법이 유사하다.
주요 어노테이션
@Inheritance(strategy = InheritanceType.XXX)
JOINED = 조인 전략
package hellojpa;
import javax.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public class Item
{
@Id @GeneratedValue
private Long id;
private String name;
private int price;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getPrice()
{
return price;
}
public void setPrice(int price)
{
this.price = price;
}
}
package hellojpa;
import javax.persistence.Entity;
@Entity
public class Movie extends Item
{
private String director;
private String actor;
public String getDirector()
{
return director;
}
public void setDirector(String director)
{
this.director = director;
}
public String getActor()
{
return actor;
}
public void setActor(String actor)
{
this.actor = actor;
}
}
try
{
Movie movie = new Movie();
movie.setDirector("aaaa");
movie.setActor("bbb");
movie.setName("바람과 함꼐 사라지다");
movie.setPrice(10000);
em.persist(movie);
em.flush();
em.clear();
Movie findMovie = em.find(Movie.class, movie.getId());
System.out.println("findMovie = " + findMovie);
tx.commit();
}
Hibernate:
select
movie0_.id as id1_2_0_,
movie0_1_.name as name2_2_0_,
movie0_1_.price as price3_2_0_,
movie0_.actor as actor1_6_0_,
movie0_.director as director2_6_0_
from
Movie movie0_
inner join
Item movie0_1_
on movie0_.id=movie0_1_.id
where
movie0_.id=?
findMovie = hellojpa.Movie@61bcbcce
insert 할시에도 2번 하게 된다. Item, Movie에게 각각 한번씩 한다.
1차 캐시를 비운후에 em.find()를 하게 되면 JPA가 알아서 Join query를 날려서 가져온다.
@DiscriminatorColumn 을 통해서 DType 현재 어떤 자식 클래스의 데이터를 담고있는 지 알려준다.
장점 = 테이블의 정규화, 외래키 참조 무결성 제약 조건활용 가능, 저장 공간의 효율화
단점 = 조회시 조인을 많이사용, 성능이저하 , 조회 쿼리가 복잡합, 데이터 저장시 Insert 2번호출
SINGLE_TABLE = 단일 테이블 전략
단일테이블의 경우 @DiscriminatorColumn 이 없어도 DTYPE 이 자동으로 생성된다. 이게 없으면 내가 Ablum인지 Movie인지 뭔지 구분을 할 수 가 없기 때문이다.
쿼리를 join 해서 날리지 않고 그냥 심플한 select 쿼리를 날림으로 성능이 좀 더 좋다.
하지만 단일테이블에 모든것을 저장하므로 테이블이커지면 상황에따라 느려질수도있다.
또한 자식 엔티티들이 모두 null을 허용해야한다. 관련이 없는것들은 null로 들어가기 때문이다.
TABLE_PER_CLASS = 구현 클래스마다 테이블 전략 // 쓰면안됨
item class 를 abstract으로 만들고 시작한다. item 테이블은 따로 생성되지 않는다.
@DiscriminatorColumn 이 동작하지않음 -> 테이블이 이미 다다르니 의미가 없다.
아이템 테이블을 없애버리고 거기있는 속성들을 다 밑으로 내리는 것이다.
하지만 Item으로 조회를 할때에는 union으로 모든 테이블을 가져오게 된다. 각 테이블(movie, book ,album) 명으로 조회할때는 문제 없긴하다.
Mapped Superclass - 매핑 정보 상속
서로 전혀다른 table이지만 속성만 상속 받고 싶을 때 쓰이는 것이다.
상속관계 매핑이 아니고 엔티티도 아니고 테이블과 매핑이 되는것도 아니다.
부모 클래스를 상속 받는 자식 클래스에 매핑정보만 제공
조회 , 검 색 불가 em.find(BaseEntity) 불가 , 직접 사용할일이 없으므로 추상 클래스 권장
package hellojpa;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass
public abstract class BaseEntity
{
private String createdBy;
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
public String getCreatedBy()
{
return createdBy;
}
public void setCreatedBy(String createdBy)
{
this.createdBy = createdBy;
}
public LocalDateTime getCreatedDate()
{
return createdDate;
}
public void setCreatedDate(LocalDateTime createdDate)
{
this.createdDate = createdDate;
}
public String getLastModifiedBy()
{
return lastModifiedBy;
}
public void setLastModifiedBy(String lastModifiedBy)
{
this.lastModifiedBy = lastModifiedBy;
}
public LocalDateTime getLastModifiedDate()
{
return lastModifiedDate;
}
public void setLastModifiedDate(LocalDateTime lastModifiedDate)
{
this.lastModifiedDate = lastModifiedDate;
}
}
@Entity
public class Member extends BaseEntity
@Entity
public class Team extends BaseEntity
try
{
Member member = new Member();
member.setUsername("user1");
member.setCreatedBy("kim");
member.setCreatedDate(LocalDateTime.now());
em.persist(member);
em.flush();
em.clear();
tx.commit();
}
Hibernate:
create table Member (
MEMBER_ID bigint not null,
createdBy varchar(255),
createdDate timestamp,
lastModifiedBy varchar(255),
lastModifiedDate timestamp,
USERNAME varchar(255),
LOCKER_ID bigint,
TEAM_ID bigint,
primary key (MEMBER_ID)
)
extend를 해준 Member 를 살펴보면 도메인에는 적혀있지 않던 createdBy ~ lastModifiedDate 까지 생겼다.
한마디로 같이 쓰고 싶은 속성을 중복없이 쓸 수 있게 해준다.
테이블과 관계 없고, 단순히 엔티티가 공통으로 사용하는 매핑정보를 모으는 역할
주로 등록일, 수정일 , 등록자, 수정자, 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용
참고: @Entity 클래스는 엔티티나 @MappedSuperclass 로 지정한 클래스만 상속가능
java - JPA: Implementing Model Hierarchy - @MappedSuperclass vs. @Inheritance - Stack Overflow
실전 예제 4 - 상속관계 매핑
요구 사항 추가
상품의 종류는 음반, 도서, 영화가 있고 이후 더 확장될 수 있다.
모든 데이터는 등록일과 수정일이 필수다.
기존의 것에 Album, Book ,Movie 가 생성되었음
테이블은 single table 로 설계가 되었음
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
public abstract class Item
public class Movie extends Item
public class Book extends Item
public class Album extends Item
자식 클래스를 구분하기위한 DTYPE 은 필수다. 이떄 전략을 바꾸고 싶다면 바로 annotation 만 JOINED 로 바꾸면된다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public abstract class Item
자식 테이블도 간단하게 생성되었다. @TABLE_PER_CLASS 도 마찬가지이다.
'WEB > JPA' 카테고리의 다른 글
김영한 (ORM 표준 JPA 프로그래밍 9) 값 타입 (0) | 2021.03.16 |
---|---|
김영한 (ORM 표준 JPA 프로그래밍 8) 프록시와 연관관계 관리 (0) | 2021.03.14 |
김영한 (ORM 표준 JPA 프로그래밍 6) 다양한 연관관계 매핑 (0) | 2021.03.08 |
김영한 (ORM 표준 JPA 프로그래밍 5) 연관관계 매핑 기초 (0) | 2021.03.07 |
김영한 (ORM 표준 JPA 프로그래밍 4) 엔티티 매핑 (0) | 2021.03.06 |