[JPA]継承関係のマッピング


この文章はインフラの金ヨンハン氏のJPA路線図をもとにまとめられたものだ.

1.継承関係のマッピング


オブジェクト向けクラス間には、次の継承関係があります.

ただし、リレーショナル・データベースでは、リレーショナルの継承はサポートされていません.逆に、オブジェクトの継承関係は、データベースのスーパータイプ、サブタイプ関係のモデリング方法でマッピングできます.

上図はItemをスーパータイプ、Album、Movie、Bookをサブタイプとしてモデリングしています.スーパータイプとサブタイプの論理モデルを実際の物理モデル(テーブル)に実装する方法は3つある.

  • 表に変換→結合ポリシー

  • 統合テーブルへの変換->単一テーブルポリシー

  • サブタイプ・テーブルへの変換->実装クラスごとのテーブル・ポリシー
  • 3つの方法はいずれもJPAで実現できる.まず主な状況を見てみましょう.
  • @Inheritance(strategy = InheritanceType.XXX)

  • JOINED:結合ポリシー

  • SINGLE TABLE:シングルテーブルポリシー

  • TABLE PER CLASS:実装クラスごとのテーブルポリシー
  • @DiscriminatorColumn(name="DTYPE")
  • @DiscrminatorValue("XXX")
  • 1.1連携戦略



    結合ポリシーは、スーパータイプ、サブタイプの論理モデルをそれぞれテーブルに移行する方法です.テーブルが別々であるため、データをクエリーするときに結合する必要があります.結合ポリシーと呼ばれます.
    コードで表示します.マッピングサブタイプは似ているので、Albumエンティティは1つしか表示されません.
    @Entity
    @Getter @Setter
    @Inheritance(strategy = InheritanceType.JOINED)
    @DiscriminatorColumn
    public abstract class Item {
    
        @Id @GeneratedValue
        @Column(name = "ITEM_ID")
        private Long id;
    
        private String name;
        private int price;
    }
    スーパータイプのItemエンティティです.スーパータイプが客体化されないように抽象クラスと宣言する.
    スーパータイプでは、マッピングポリシーは、@Inheritance(strategy = InheritanceType.JOINED)によって結合ポリシーとして指定されます.@DiscriminatorColumn注記は、区切り文字列を指します.結合ポリシーと単一テーブルポリシーでは、区切り文字列が必要です.セパレータ列では、どのサブタイプのデータを区別します.区切り欄が必要な場合は省略すると自動的に追加されますが、明確に記入することをお勧めします.区切りバーの名前はデフォルトで「DTYPE」です.希望する値として指定できますが、特別な理由がない場合は、デフォルト値を受け入れることをお勧めします.
    @Entity
    @Getter @Setter
    @DiscriminatorValue("A")
    public class Album extends Item {
    
        private String artist;
    }
    サブタイプAlbumはスーパータイプItemを継承します.@DiscriminatorValueにより、区切り欄の値を決定することができる.デフォルトはエンティティ名です.
    署名戦略のメリットとデメリットを見てみましょう.

  • 長所

  • テーブルが正規化された.

  • 外部キーを使用して整合性制約を参照できます.

  • ストレージ容量が効率的になります.

  • 短所

  • 照会にはサインが必要です.結合が必要なため、単一のテーブル・ポリシーよりもパフォーマンスが低下する可能性があります.

  • 結合が必要なため、クエリー・クエリーは単一のテーブル・ポリシーよりも複雑です.

  • テーブルが別々なので、保存時にINSERT SQLが2回呼び出されます.単一のテーブル・ポリシーに比べてパフォーマンスが低下します.
  • 欠点は性能が低下する可能性があることですが、実際には、最近のコンピュータの性能はよく、データが多くない限り、性能は低下しません.次に説明する単一テーブルポリシーは結合する必要はありませんが、nullデータが多いため、結合ポリシーよりもパフォーマンスが低下する可能性があります.
    結合ポリシーは、継承関係をマッピングするポリシーの中で、データベースの観点から最も正規化された簡潔で定式化されたポリシーです.

    1.2単一テーブルポリシー


    結合ポリシーがスーパータイプとサブタイプを正規化し、それぞれ異なるテーブルに格納する場合、単一のテーブルポリシーは、その名の通り、すべてのデータを1つのテーブルに集約するポリシーです.

    結合ポリシーと同様に、分子タイプを区別するには、セパレータ列を使用する必要があります.コードで表示します.
    @Entity
    @Getter @Setter
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn
    public abstract class Item {
    
        @Id @GeneratedValue
        @Column(name = "ITEM_ID")
        private Long id;
    
        private String name;
        private int price;
    }
    @Entity
    @Getter @Setter
    @DiscriminatorValue("A")
    public class Album extends Item {
    
        private String artist;
    }
    署名戦略では、@Inheritance(strategy = InheritanceType.SINGLE_TABLE)によって戦略が変更された以外は、変更されたコードはありません.継承関係マッピングポリシーを変更すると、JPAは自動的にエンティティを適切なテーブルにマッピングします.これがORMの強みです.ORMを使用せずに継承関係マッピングポリシーを変更した場合は、テーブルタイプのSQLを大幅に変更する必要があります.
    単一テーブルポリシーのメリットとデメリットを見てみましょう.

  • 長所

  • 結合は必要ないため、クエリーのパフォーマンスが速いのが一般的です.

  • 結合が不要なため、クエリーは簡単です.

  • 短所

  • サブエンティティにマッピングされるすべてのカラムにnullを許可する必要があります.

  • 表の列長が大きくなると、場合によってはクエリのパフォーマンスが逆に遅くなります.
  • 1つのテーブル・ポリシーは、1つのテーブルにサブタイプのすべてのデータが含まれているため、テーブルを大きくします.テーブルが1つしか使われていないので、操作が便利です.
    結合ポリシーは、ワークベンチを正規化するための固定的で理想的なポリシーです.単一テーブルポリシーは、テーブルを操作しやすい実用的なポリシーです.場合によっては両者の中から一つを選べばよい.単一のテーブル・ポリシーでは、正規化を放棄する必要があり、null値も多くありますが、大きな問題がないと思う場合は使用できます.結合ポリシーは正規化されているため、テーブルが多くなり、管理が困難になるため、単一のテーブルポリシーよりも悪い場合があります.

    1.3実装クラスごとのテーブルポリシー


    スーパータイプとは、テーブルにマッピングせずにサブタイプのみをテーブルにマッピングする方法です.

    以前のコードでは、スーパータイプの@Inheritanceのポリシー設定を変更するだけでよい.コードをスキップして、すぐにメリットとデメリットを理解します.

  • 長所

  • 処理を明確に区別できるのはサブタイプのみです.

  • 単一のテーブルポリシーでは、不可能なnot null制約を使用できます.

  • 短所

  • 複数のサブテーブルが一緒にクエリされると、パフォーマンスが遅くなります.(UNIX演算発生)

  • サブテーブルではクエリーをマージするのは難しいです.
  • 要するに、この戦略は実務では使用できない.各サブタイプは、それぞれのテーブルに明確に分割されます.しかし,概念的には,アイテム(Item)というスーパータイプに属する各サブタイプテーブルを統合し,管理を非常に困難にする.たとえば、すべてのアイテムの平均価格を求めるクエリーを作成するのは難しいです.継承関係マッピングでは、結合ポリシー、単一テーブルポリシーのいずれかを選択できます.

    2.共通属性がある場合-@MappedSuperclass


    オブジェクト向けの場合、継承はプロパティを簡単に再利用するために使用できます.下図のようです.

    MemberクラスとSellerクラスには共通属性idとnameがある.各クラスで属性を定義できますが、共通の親クラスで属性を定義し、クラスを設計して属性を継承することもできます.
    継承関係マッピングと混同することはできません.継承関係マッピングのように、サブクラスアルバム(Album)を親アイテム(Item)タイプに従属するわけではありません.すなわち,単純に共通属性を再利用するために継承を用いる.親はエンティティではなく、属性のみを子に継承します.エンティティではないため、親クラスのクエリーや検索はもちろんできません.親クラスは共通属性の集合にすぎず、オブジェクト化する必要はありません.したがって、抽象クラスとして作成することをお勧めします.
    MemberおよびSellerエンティティは、下図のテーブルにマッピングされます.

    id,nameという名前の列が存在するが,概念的には2つのテーブルは関連のない独立したテーブルである.
    例を見てみましょう.
    @MappedSuperclass
    @Getter @Setter
    public abstract class BaseEntity {
    
        private String createdBy;
        private LocalDateTime createdAt;
        private LocalDateTime lastModifiedBy;
        private LocalDateTime lastModifiedAt;
    }
    実際の作業では、主にすべてのエンティティで登録日、変更日、登録者、および変更者を追跡します.
    共通属性を収集するBaseEntityクラスが作成されました.実際のオブジェクト化がないため、抽象クラスとして作成されます.上位クラスは、属性情報を単純に収集するクラスとして@MappedSuperclassにより明確に示さなければならない.@Entityによってエンティティとして宣言されたクラスは、別のエンティティクラスまたは@MappedSuperclassとして指定されたクラスのみを継承できます.
    @Entity
    @Getter @Setter
    @Inheritance(strategy = InheritanceType.JOINED)
    @DiscriminatorColumn
    public abstract class Item extends BaseEntity {
    
        @Id @GeneratedValue
        @Column(name = "ITEM_ID")
        private Long id;
    
        private String name;
        private int price;
    }
    継承関係マッピングの例で使用したItemクラスはBaseEntityクラスを継承します.Itemを継承するAlbum、Book、Movieも共通属性を継承します.