2.2.3. Mapping identifier properties. IDのマッピング*1

<2.2.2.2. Declaring column attributes | 目次 | 2.2.4. Mapping inheritance>

@Id アノテーションはエンティティBeanの識別子を定義するよ。このプロパティはアプリケーションでもセットできるけど、Hibernateで生成させたほうがよいよ。@GeneratedValueアノテーションで生成戦略を定義できるよ。

  • AUTO - IDENTITY か SEQUENCE か TABLE を元のDBによって自動につけるよ
  • TABLE - IDを持つテーブル
  • IDENTITY - IDカラム
  • SEQUENCE - シーケンス

HibernateEJB3 より多くの IDジェネレータがあるよ。詳細は Hibernate Annotation Extensions を見てね。

次の例では、SEQ_STORE を使ったシーケンスジェネレータを示すよ。

@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
public Integer getId() { ... }

次の例は IDENTITY ジェネレータだよ。

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId() { ... }

AUTOジェネレータは、アプリケーションの移植性がよいよ。ID生成の設定は共通化できるよ。@SequenceGenerator、@TableGenerator を使ったいろんな設定があるよ。ジェネレータの範囲はアプリケーション全体か、クラス毎ができるよ。クラス定義ジェネレータは、クラスの外から見えなくて、アプリケーションレベルのジェネレータを上書きできるよ。アプリケーションレベルのジェネレータはXMLレベルで設定するよ。(Chapter Overriding metadata through XML, Overriding metadata through XML を参照)

<table-generator name="EMP_GEN"
            table="GENERATOR_TABLE"
            pk-column-name="key"
            value-column-name="hi"
            pk-column-value="EMP"
            allocation-size="20"/>

//and the annotation equivalent

@javax.persistence.TableGenerator(
    name="EMP_GEN",
    table="GENERATOR_TABLE",
    pkColumnName = "key",
    valueColumnName = "hi"
    pkColumnValue="EMP",
    allocationSize=20
)

<sequence-generator name="SEQ_GEN" 
    sequence-name="my_sequence"
    allocation-size="20"/>

//and the annotation equivalent

@javax.persistence.SequenceGenerator(
    name="SEQ_GEN",
    sequenceName="my_sequence",
    allocationSize=20
)

ジェネレータの定義に JPA XML(META-INF/orm/xmlのような)が使われると、EMP_GEN と SEQ_GEN はアプリケーションレベルになるよ。EMP_GEN は
max_lo 20*1 の Hiloアルゴリズムを使った、テーブルベースのIDジェネレータだよ。hi値は GENERATOR_TABLE に保存されるよ。pkColumnName "key" が等しい pkColumnValue "EMP" の行へ情報が保存されて、valueColumnName "hi" は次に高い使われる値を持っているよ。*2

SEQ_GEN は my_sequence という名前のシーケンスを使ったジェネレータだよ。hiloアルゴリズムをベースとしたこのシーケンスで使われるアロケーションサイズは20だよ。このバージョンのHibernate Annotationsでは、シーケンスジェネレータの initialValue は扱わないよ。デフォルトのアロケーションサイズは50だから、もし、シーケンスを使って毎回値をピックアップしたいなら、アロケーションサイズを1にしてね。

注意
パッケージレベルの定義は EJB3.0 仕様では定義されてないけど、パッケージレベルに @GenericGenerator が使えるよ(Section 2.4.Identifier, “Identifier”を見てね)。

次の例は、クラス範囲のシーケンスジェネレータの定義だよ。

@Entity
@javax.persistence.SequenceGenerator(
    name="SEQ_STORE",
    sequenceName="my_sequence"
)
public class Store implements Serializable {
    private Long id;

    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
    public Long getId() { return id; }
}

このクラスは my_sequence という名前のシーケンスを使って、SEQ_STOREジェネレータは他のクラスからは見えないよ。org.hibernate.test.annotations.id パッケージの テストにもっと例があるよ。
いくつかの記法で、複合主キーを定義できるよ。

@IdClass は、EJB2 を使った人なら知ってるけど、Hibernate ユーザには初めてかもしれないね。複合主キークラスは、エンティティクラスのフィールドやプロパティとつながっていて、名前も型も同じでないといけないよ。次の例を見て!

@Entity
@IdClass(FootballerPk.class)
public class Footballer {
    //part of the id key
    @Id public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    //part of the id key
    @Id public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getClub() {
        return club;
    }

    public void setClub(String club) {
        this.club = club;
    }

    //appropriate equals() and hashCode() implementation
}

@Embeddable
public class FootballerPk implements Serializable {
    //same name and type as in Footballer
    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    //same name and type as in Footballer
    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    //appropriate equals() and hashCode() implementation
}

見ての通り、@IdClass は対応する主キークラスを指すよ。

EJB3仕様ではサポートされないけど、Hibernateでは複合主キーの関連を定義できるよ。簡単に使い方を示すよ。

@Entity
@AssociationOverride( name="id.channel", joinColumns = @JoinColumn(name="chan_id") )
public class TvMagazin {
    @EmbeddedId public TvMagazinPk id;
    @Temporal(TemporalType.TIME) Date time;
}

@Embeddable
public class TvMagazinPk implements Serializable {
    @ManyToOne
    public Channel channel;
    public String name;
    @ManyToOne
    public Presenter presenter;
}

<2.2.2.2. Declaring column attributes | 目次 | 2.2.4. Mapping inheritance>

*1:Hiloアルゴリズムのパラメータ。allocation-sizeで指定されている。

*2:訳適当。。