1. 소개

상속은 Java의 핵심 개념 중 하나입니다. 따라서 대부분의 도메인 모델이 이를 사용하는 것은 놀라운 일이 아닙니다. 그러나 불행하게도 이 개념은 관계형 데이터베이스에는 존재하지 않으며 상속 계층 구조를 관계형 테이블 모델에 매핑하는 방법을 찾아야 합니다.

JPA와 Hibernate는 상속 계층 구조를 다양한 테이블 모델에 매핑하는 다양한 전략을 지원합니다. SingleTable 전략 을 설명하는 일반적인 Hibernate 문제에 대한 70개 이상의 솔루션인 내 새 책 Hibernate Tips – 70개 이상의 솔루션의 한 장을 살펴보겠습니다 . 상속 계층 구조의 모든 클래스를 동일한 데이터베이스 테이블에 매핑합니다.

나는 Hibernate Tips 책 에서 Hibernate의 다른 상속 매핑 전략을 설명 한다. 기본 및 고급 매핑, 로깅, Java 8 지원, 캐싱, 정적 및 동적으로 정의된 쿼리와 같은 주제에 대해 70개 이상의 즉시 사용 가능한 레시피가 포함된 요리책입니다.


2. Hibernate 팁 – 상속 계층 구조를 하나의 테이블에 매핑하는 방법

2.1. 문제

내 데이터베이스에는 엔터티의 상속 계층 구조에 매핑하려는 하나의 테이블이 포함되어 있습니다. 이러한 매핑을 어떻게 정의합니까?

2.2. 해결책

JPA와 Hibernate는 엔터티를 다른 테이블 구조에 매핑할 수 있는 다른 상속 전략을 지원합니다. SingleTable 전략은 그 중 하나이며 엔터티의 상속 계층 구조를 단일 데이터베이스 테이블에 매핑합니다.

SingleTable 전략 에 대해 자세히 설명하기 전에 엔터티 모델을 살펴보겠습니다 . 작성자 는 BooksBlogPosts 와 같은 다양한 종류의 발행물 을 작성할 수 있습니다 . Publication 클래스는 Book BlogPost 클래스 의 상위 클래스입니다.

상속 엔터티 모델

SingleTable 전략 은 상속 계층의 세 엔터티를 게시 테이블에 매핑합니다.

새로운 상속 단일 테이블

이 상속 전략을 사용하려면 수퍼클래스에 @Inheritance 어노테이션을 추가하고 전략 속성 의 값으로 InheritanceType.SINGLE_TABLE 을 제공해야 합니다.

판별자 값의 이름을 정의하기 위해 @DiscriminatorColumn 어노테이션으로 수퍼클래스에 어노테이션을 달 수도 있습니다 . Hibernate는 이 값을 사용하여 데이터베이스 레코드를 매핑해야 하는 엔터티를 결정합니다. 다음 코드 스니펫에서와 같이 판별자 열을 정의하지 않으면 Hibernate 및 기타 모든 JPA 구현에서 DTYPE 열을 사용합니다 .

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Publication {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;

    @Version
    private int version;

    private String title;

    private LocalDate publishingDate;
	
    @ManyToMany
    @JoinTable(
      name="PublicationAuthor",
      joinColumns={@JoinColumn(name="publicationId", referencedColumnName="id")},
      inverseJoinColumns={@JoinColumn(name="authorId", referencedColumnName="id")})
    private Set<Author> authors = new HashSet<Author>();

    ...
}

서브클래스는 슈퍼클래스를 확장해야 하며 @Entity 어노테이션으로 어노테이션을 추가해야 합니다.

JPA 사양은 또한 이 엔터티 클래스에 대한 구분자 값을 정의하기 위해 @DiscriminatorValue 어노테이션으로 어노테이션을 달 것을 권장합니다. 이 어노테이션을 제공하지 않으면 JPA 구현에서 판별자 값을 생성합니다.

그러나 JPA 사양은 판별자 값을 생성하는 방법을 정의하지 않으며 애플리케이션이 다른 JPA 구현에 이식되지 않을 수 있습니다. Hibernate는 판별자로 간단한 엔터티 이름을 사용합니다.

@Entity
@DiscriminatorValue("Book")
public class Book extends Publication {

    private int numPages;

    ...
}

SingleTable 전략 은 특정 엔터티를 선택하거나 다형성 쿼리를 수행하거나 다형성 연결을 트래버스하려는 경우 복잡한 쿼리를 생성하기 위해 Hibernate를 요구하지 않습니다.

Author a = em.find(Author.class, 1L);
List<Publication> publications = a.getPublications();

모든 엔터티는 동일한 테이블에 저장되며 Hibernate는 추가 JOIN 절 없이 거기에서 엔터티를 선택할 수 있습니다.

15:41:28,379 DEBUG [org.hibernate.SQL] - 
    select
        author0_.id as id1_0_0_,
        author0_.firstName as firstNam2_0_0_,
        author0_.lastName as lastName3_0_0_,
        author0_.version as version4_0_0_ 
    from
        Author author0_ 
    where
        author0_.id=?
15:41:28,384 DEBUG [org.hibernate.SQL] - 
    select
        publicatio0_.authorId as authorId2_2_0_,
        publicatio0_.publicationId as publicat1_2_0_,
        publicatio1_.id as id2_1_1_,
        publicatio1_.publishingDate as publishi3_1_1_,
        publicatio1_.title as title4_1_1_,
        publicatio1_.version as version5_1_1_,
        publicatio1_.numPages as numPages6_1_1_,
        publicatio1_.url as url7_1_1_,
        publicatio1_.DTYPE as DTYPE1_1_1_ 
    from
        PublicationAuthor publicatio0_ 
    inner join
        Publication publicatio1_ 
            on publicatio0_.publicationId=publicatio1_.id 
    where
        publicatio0_.authorId=?

2.3. 소스 코드

에서 이 Hibernate 팁에 대한 실행 가능한 테스트 사례가 있는 프로젝트의 다운로드 링크를 찾을 수 있습니다 .

2.4. 더 알아보기

상속 계층의 엔터티를 여러 데이터베이스 테이블에 매핑할 수도 있습니다. 상속 계층 구조를 여러 테이블에 매핑하는 방법
장에서 그 방법을 보여줍니다 .

 

3. 요약

이 Hibernate Tip에서 본 것처럼 JPA와 Hibernate는 상속 계층 구조를 단일 데이터베이스 테이블에 매핑하는 쉬운 옵션을 제공합니다. 수퍼클래스에 @Inheritance(strategy = InheritanceType.SINGLE_TABLE) 어노테이션을 달고 서브클래스에도 @DiscriminatorValue(“Book”) 어노테이션을 달아야 합니다.

나의 새 책 Hibernate Tips: More than 70 Solutions to common Hibernate problems 에서 이와 같은 레시피를 더 많이 얻을 수 있습니다 . 기본 및 고급 매핑, 로깅, Java 8 지원, 캐싱, 정적 및 동적으로 정의된 쿼리와 같은 주제에 대해 70개 이상의 즉시 사용 가능한 레시피를 제공합니다. 

Persistence footer banner