Hibernate Tips Book抜粋:継承階層を1つのテーブルにマッピングする方法

1前書き

継承はJavaの重要な概念の1つです。そのため、ほとんどのドメインモデルで使用されているのは当然のことです。しかし残念ながら、この概念はリレーショナルデータベースには存在しないため、継承階層をリレーショナルテーブルモデルにマッピングする方法を見つける必要があります。

JPAとHibernateは、継承階層をさまざまなテーブルモデルにマッピングするさまざまな戦略をサポートしています。私の新しい本の章を見てみましょう。ここで私は SingleTable 戦略を説明します。継承階層のすべてのクラスを同じデータベーステーブルにマップします。

Hibernateの他の継承マッピング戦略については、私のhttps://www.amazon.com/Hibernate-Tips-solutions-common-problems-ebook/dp/B06XXGYZHS/[Hibernate Tips book]で説明します。基本マッピングと詳細マッピング、ロギング、Java 8サポート、キャッシュ、静的に定義されたクエリ、動的に定義されたクエリなど、70種類以上の調理済みレシピが用意されています。あなたはhttps://www.amazon.com/Hibernate-Tips-solutions-common-problems-ebook/dp/B06XXGYZHS/[Amazonで今週それをゲット]ことができるのはたったの2.99ドルの特別な発売価格です。


2 Hibernateのヒント - 継承階層を1つのテーブルにマッピングする方法

2.1. 問題

私のデータベースには1つのテーブルが含まれています。このテーブルをエンティティの継承階層にマッピングします。そのようなマッピングをどのように定義しますか?

2.2. 溶液

JPAとHibernateはエンティティを異なるテーブル構造にマッピングすることを可能にする異なる継承戦略をサポートします。 SingleTable 戦略はその1つで、エンティティの継承階層を単一のデータベーステーブルにマッピングします。

SingleTable 戦略の詳細を説明する前に、エンティティモデルを見てみましょう。 Authors は、 Books BlogPosts など、さまざまな種類の Publications を作成できます。 Publication クラスは、 Book および BlogPost クラスのスーパークラスです。

SingleTable 戦略は、継承階層の3つのエンティティを publication テーブルにマッピングします。

この継承戦略を使用したい場合は、スーパークラスに @ Inheritance アノテーションを付け、 Strategy 属性の値として 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. ソースコード

book に、このHibernateのヒントに関する実行可能なテストケースを含むプロジェクトのダウンロードリンクがあります。

2.4. もっと詳しく知る

継承階層のエンティティを複数のデータベーステーブルにマッピングすることもできます。 +継承階層を複数のテーブルにマッピングする方法__の章で、その方法を紹介します。

3概要

このHibernateのヒントで見たように、JPAとHibernateは継承階層を単一のデータベーステーブルにマッピングするための簡単なオプションを提供します。

スーパークラスに @ Inheritance(strategy = InheritanceType.SINGLE TABLE) というアノテーションを付けるだけで、サブクラスに @ DiscriminatorValue(“ Book”)__というアノテーションも付ける必要があります。