2.2.4. Mapping inheritance. マッピング継承

<2.2.3. Mapping identifier properties | 目次 | 2.2.5. Mapping entity bean associations/relationships>

EJB3 は3つの継承の方法をサポートしてるよ。

  • クラス毎のテーブル戦略: Hibernateでの
  • クラス階層毎に1つのテーブル戦略: Hibernateでの
  • ジョインドサブクラス戦略: Hibernateでの

@Inheritance を使って、クラス階層の一番上のエンティティのクラスレベルに、選んだ戦略を定義するよ。

注意
インターフェースへのアノテーションは現在サポートされてないよ。

2.2.4.1. Table per class クラス毎テーブル

この戦略はあちこちで言われている欠点がいっぱいあるよ(特に、ポリモロフィックなクエリや関連で)。Hibernate では、SQL の UNION クエリでこの戦略を実装しているよ。普通これは、継承階層の一番上で使われるよ。

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Flight implements Serializable {

この戦略は、双方向の1対他関係をサポートするよ。この戦略は、IDをいくつかのテーブルで共有するので、IDENTITY ジェネレータをサポートしないよ。だから、この戦略を使うときは、AUTO や IDENTITY は使っちゃいけないよ。

2.2.4.2. Single table per class hierarchy クラス階層毎テーブル

全てのスーパークラスからサブクラスのプロパティは、同じテーブルにマッピングされて、インスタンスは特殊な識別カラムで区別されるよ。

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="planetype",
    discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue("Plane")
public class Plane { ... }

@Entity
@DiscriminatorValue("A320")
public class A320 extends Plane { ... }

Plane は親クラスで、継承戦略に InheritanceType.SINGLE_TABLE を定義しているよ。@DiscriminatorColumn アノテーションで、識別カラムを定義して、識別カラムは識別タイプも定義できるよ。@DiscriminatorValue で、クラス階層を区別するのに使われる値を定義しているよ。これらの属性は全部デフォルト値をもってるよ。識別カラムのデフォルト名は DTYPEだよ。デフォルトの識別値は、DiscriminatorType.STRING のエンティティ名(@Entity.name)だよ。A320 はサブクラスで、デフォルトを使わないなら、識別値だけ定義しなければいけないよ。戦略と識別タイプは暗黙だよ。

@Inheritance と @DiscriminatorColumn はエンティティ階層の一番上だけに定義しないといけないよ。

2.2.4.3. Joined subclasses 結合サブクラス

@PrimaryKeyJoinColumn と @PrimaryKeyJoinColumns アノテーションは、結合されたサブクラステーブルの主キーを定義するよ。

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Boat implements Serializable { ... }

@Entity
public class Ferry extends Boat { ... }

@Entity
@PrimaryKeyJoinColumn(name="BOAT_ID")
public class AmericaCupClass  extends Boat { ... }

上の全てのエンティティは JOINED 戦略を使っているよ。Ferry テーブルは、同じ名前の主キーを使って、Boatテーブルと結合されるよ。AmericaCupClass テーブルは、Boat.id = AmericaCupClass.BOAT_ID の結合条件でBoatテーブルと結合されるよ。

2.2.4.4. Inherit properties from superclasses 親クラスから継承するプロパティ
普通のマッピングされたエンティティのようにテーブルに含まずに、共通のプロパティを共有することは、時に役に立つよ。そういうときは、@MappedSuperclass が使えるよ。

@MappedSuperclass
public class BaseEntity {
    @Basic
    @Temporal(TemporalType.TIMESTAMP)
    public Date getLastUpdate() { ... }
    public String getLastUpdater() { ... }
    ...
}

@Entity class Order extends BaseEntity {
    @Id public Integer getId() { ... }
    ...
}

データベースで、この階層は id、lastUpdate、lastUpdater カラムを持つ Order テーブルであらわされるよ。親クラスのプロパティのマッピングは、サブクラスにコピーされるよ。この親クラスは、階層のルートじゃなくてもよいよ。

注意
@MappedSuperclass としてマッピングされていない親クラスのプロパティは無視されるよ。
注意
アクセスタイプ(フィールド、またはメソッド)は ルートエンティティから継承されるよ。@AccessTypeを使うまで。
注意
@Embeddable オブジェクトにも同じ考えが適応されるよ。けど、標準的なEJB3 の機能とは思わないでね。
注意
@MappedSuperclass は、クラス階層の途中にもつけられるよ。
注意
@MappedSuperclass も @Entity も付いてないものは無視されるよ。

@AttributeOverride で、親クラスのカラム定義を上書きできるよ。

@MappedSuperclass
public class FlyingObject implements Serializable {

    public int getAltitude() {
        return altitude;
    }

    @Transient
    public int getMetricAltitude() {
        return metricAltitude;
    }

    @ManyToOne
    public PropulsionType getPropulsion() {
        return metricAltitude;
    }
    ...
}

@Entity
@AttributeOverride( name="altitude", column = @Column(name="fld_altitude") )
@AssociationOverride( name="propulsion", joinColumns = @JoinColumn(name="fld_propulsion_fk") )
public class Plane extends FlyingObject {
    ...
}

altitude プロパティは、Plane テーブルの fld_altitude カラムに永続化され、propulsion 関連は fld_propulsion_fk 外部キーが使われるよ。

@AttributeOverride、@AssociationOverride を、@Entiyクラス、@MappedSuperClassクラス、@Embeddableオブジェクトを指しているプロパティに定義できるよ。<2.2.3. Mapping identifier properties | 目次 | 2.2.5. Mapping entity bean associations/relationships>