2.2.3. ID プロパティのマッピング
@Id アノテーションを使用すると、エンティティ Bean の ID となるプロパティを定義できます。このプロパティは、アプリケーション自体によって設定したり、Hibernate (推奨される方法) によって生成したりできます。@GeneratedValue アノテーションにより ID 生成方針を定義できるようになります。
- AUTO - 基礎となる DB に応じて ID カラム、シーケンス、またはテーブルのいずれか
- TABLE - ID を保持するテーブル
- IDENTITY - ID カラム
- SEQUENCE - シーケンス
Hibernate は、基本的な EJB3 のものよりも多くの ID ジェネレータを提供します。詳細については、「Hibernate Annotation 拡張機能」 を参照してください。
以下の例は、SEQ_STORE 設定 (以下参照) を使用したシーケンスジェネレータを示しています。
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
public Integer getId() { ... }
次の例では、ID ジェネレータが使用されています。
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId() { ... }
AUTO ジェネレータはポータブルなアプリケーションに推奨されるタイプです (複数の DB ベンダー間)。ジェネレータ属性を持つ複数の @Id マッピングに対して ID 生成の設定を共有できます。@SequenceGenerator と @TableGenerator を使用して複数の設定を利用できます。ジェネレータのスコープはアプリケーションまたはクラスのいずれかです。クラスが定義されたジェネレータは、そのクラス以外で不可視であり、アプリケーションレベルのジェネレータよりも優先されます。アプリケーションレベルのジェネレータは XML レベルで定義されます (3章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 の hilo アルゴリズムを使用してテーブルベースの ID ジェネレータを定義します。hi value は table "GENERATOR_TABLE" に保持されます。情報は、pkColumnName "key" が pkColumnValue "EMP" に等しく、カラム valueColumnName "hi" に次に使用される high value が含まれる行に保持されます。
SEQ_GEN は my_sequence という名前のシーケンスを使用してシーケンスジェネレータを定義します。このシーケンスベースの hilo アルゴリズムに使用されるアロケーションサイズは 20 です。このバージョンの Hibernate Annotations はシーケンスジェネレータで initialValue を処理しないことに注意してください。デフォルトのアロケーションサイズは 50 です。したがって、シーケンスを使用し、常にその値を取得したい場合は、アロケーションサイズを 1 に設定する必要があります。
注記
パッケージレベル定義は EJB 3.0 仕様でサポートされなくなりました。ただし、
@GenericGenerator をパッケージレベルで使用できます (「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 パッケージで Hibernate Annotations テストをチェックできます。
複数の構文を使用して復号プライマリキーを定義できます。
- コンポーネントプロパティを @Id としてアノテートし、コンポーネントクラスを @Embeddable にします。
- コンポーネントプロパティを @EmbeddedId としてアノテートします。
- クラスを @IdClass としてアノテートし、プライマリキーで関連するエンティティの各プロパティを @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 では、複合 ID 内の関係を定義できます。このためには通常のアノテーションを使用してください。
@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;
}