🍌
JPAの@Inheritance(継承マッピング)とは
継承関係マッピング
- 関係型DBには継承関係が存在しないです。
- SuperタイプーSubタイプ関係がオブジェクトの継承と一番類似しています。
- つまり、継承関係マッピングとはオブジェクトの継承関係をRDBのSuperタイプーSubタイプ関係にマッピングする事です。
三つの戦略
具現化方法には三つの戦略が存在します。
@Inheritance(strategy=InheritanceType.XXX)
* JOINED
: Join戦略
* SINGLE_TABLE
: 単一テーブル戦略
* TABLE_PER_CLASS
: クラス別テーブル戦略
@DiscriminatorColumn (区分カラム)
@Entity
@Getter
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public abstract class Item { ... }
- 必須で入れた方がいいです。
- Superタイプにつける
-
属性
-
name
:@DiscriminatorColumn(name=“DTYPE”)
カラム名を指定可能- 基本値 :
DTYPE
- 基本値 :
-
-
SINGLE_TABLE
戦略使う場合@DisciriminatorColumn
宣言しなくても自動的にDTYPE
カラムが追加されカラムの値としてはSubタイプのエンティティ名が入ります。
@DiscriminatorValue
- 区分カラムに入る値を指定
- Subタイプの方につける
- 基本値 : エンティティ名が入ります。
-
@DiscriminatorValue(“XXX”)
: 名前指定可能
-
@Entity
@DiscriminatorValue("BOOK")
public class Book extends Item { ... }
@Inheritance
- 継承関係マッピングで一番重要なアノテーション。
- 三つの戦略を提供する
-
@Inheritance(strategy=InheritanceType.XXX)
-
JOINED
: Join戦略 -
SINGLE_TABLE
: 単一テーブル戦略 -
TABLE_PER_CLASS
: クラス別テーブル戦略
-
-
strategy
指定がない場合基本SINGLE_TABLE
戦略を使用
@Entity
@Getter
@Inheritance // strategy指定がない場合基本SINGLE_TABLE戦略を使用
@DiscriminatorColumn
public class Item extends BaseEntity{
@Id
@Column(name = "item_id")
private Long id;
private String name;
private Integer price;
}
Join戦略(InheritanceType.JOINED)
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Getter @Setter
@DiscriminatorColumn(name = "dtype") // default = "DTYPE"
public abstract class Item {
@Id
@Column(name = "item_id")
private Long id;
private String name;
private Integer price;
}
@Entity
@DiscriminatorValue("A")
@Getter @Setter
public class Alcohol extends Item{
private String level;
}
- 一番正規化された戦略です。
- 子テーブル識別子はPKでありながらFKです。
-
JOINED
戦略は抽象クラスで宣言してもテーブルが生成される。- 親クラスだけでインスタンスを生成して何かをやるのなら抽象クラスではなく一般クラスで作るべきです。
- 一番基本として使わなければならない戦略です。
- ビジネス的に重要で複雑なら
JOIN
戦略を選ぶのが良いです。 - Subタイプにも
@Entity
宣言必須です。 - 区分カラムが無くても
JOINED
戦略が具現化されるが区分及び運用の効率性のためDTYPE(@DiscriminatorColumn)
を入れた方がいい-
@DiscriminatorColumn
省略するとDTYPE
カラムは生成されないです。
-
Join戦略の長所
- テーブルの正規化
- 正規化を通じた重複防止、保存空間の効率化
- 外来キー制約の活用ができます。
Join戦略の短所
- 照会するときJOINを多く使います、それにより性能的に問題があり可能性があります。
- 照会クエリがすごく複雑になる可能性があります。
- テータ保存時
insert
クエリが2回投げられます。
Hibernate:
/* insert jpabasic.Snack
*/ insert
into
Item
(name, price, dtype, item_id)
values
(?, ?, 'S', ?)
Hibernate:
/* insert jpabasic.Snack
*/ insert
into
Snack
(texture, item_id)
values
(?, ?)
単一テーブル戦略(InheritanceType.SINGLE_TABLE)
-
@Inheritance
のみ宣言するとSINGLE_TABLE
戦略を使用する、JPAの基本戦略であります。 - 本当に単純で拡張の可能性が低い時に
SINGLE_TABLE
戦略を使用することが良いです。 - 区分カラムは必須です。
-
@DiscriminatorColumn
を宣言しなくてもHibernateが自動的に指定する。
-
単一テーブル戦略の長所
- JOINが要らないので一般的に照会性能が早いです。
- 照会クエリが単純です。
-
JOINED
とは違い当たり前だがinsert
が一回だけ投げられる。
単一テーブル戦略の短所
- 子エンティティをマッピングしたテーブルのカラムは全て
null
を許さなければならない。 - 単一テーブルに全てを入れるのでテーブルが大きくなりがちです、それにより状況によっては照会性能がむしろ遅くなる可能性もあります。
クラス別テーブル戦略(InheritanceType.TABLE_PER_CLASS)
- SUPER TYPEを必ず抽象(
abstract
)クラスに作らなければならない。- 抽象クラスではなく一般クラスである場合JPAがSUPER TYPEもテーブルを作ってしまう
- この戦略は非推奨である。
クラス別テーブル戦略長所
- SUB TYPEを明確に区分して処理するとき効率的であります。
-
not null
制約が使えます。
クラス別テーブル戦略短所
- SUPER TYPEで照会する時
union
を利用して全てのテーブルを探らなければならない。すごく非効率的である。 - 幾つの子テーブルを一緒に照会する時性能が悪い
- 子テーブルを合わしてクエリすることが難しい
-
GenerationType.IDENTITY
戦略を使用することが出来ない。-
GenerationType.IDENTITY
はDBにキー生成を任せる戦略であるがTABLE_PER_CLASS
に使用すると格テーブル毎にIDが生成されUNIQUEである事を担保できなくなりエラーが出る。なので他のキー生成戦略であるSEQUENCEやTABLE戦略を使うことでSUB TYPEのエンティティたちが同一のSEQUENCEを参照することでUNIQUE性を担保できるようにしなければならない。
-
(次)JPAのProxy
Discussion