Hibernate.orgCommunity Documentation
オブジェクト/リレーショナルマッピングは通常 XML ドキュメントで定義します。マッピングドキュメントは、読みやすく手作業で編集しやすいようにデザインされています。マッピング言語は Java 中心、つまりテーブル定義ではなく永続クラスの定義に基づいて構築されています。
多くの Hibernate ユーザーは XML マッピングの記述を手作業で行いますが、 XDoclet, Middlegen, AndroMDA というようなマッピングドキュメントを生成するツールがいくつか存在することを覚えておいてください。
サンプルのマッピングから始めましょう:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="eg">
<class name="Cat"
table="cats"
discriminator-value="C">
<id name="id">
<generator class="native"/>
</id>
<discriminator column="subclass"
type="character"/>
<property name="weight"/>
<property name="birthdate"
type="date"
not-null="true"
update="false"/>
<property name="color"
type="eg.types.ColorUserType"
not-null="true"
update="false"/>
<property name="sex"
not-null="true"
update="false"/>
<property name="litterId"
column="litterId"
update="false"/>
<many-to-one name="mother"
column="mother_id"
update="false"/>
<set name="kittens"
inverse="true"
order-by="litter_id">
<key column="mother_id"/>
<one-to-many class="Cat"/>
</set>
<subclass name="DomesticCat"
discriminator-value="D">
<property name="name"
type="string"/>
</subclass>
</class>
<class name="Dog">
<!-- mapping for Dog could go here -->
</class>
</hibernate-mapping
>
マッピングドキュメントの内容を説明します。ただし、ここでは Hibernate が実行時に使うドキュメント要素と属性についてのみ説明します。マッピングドキュメントは、いくつかのオプション属性と要素を含んでいます(例えば not-null
属性)。それらはスキーマエクスポートツールが出力するデータベーススキーマに影響を与えるものです。
XML マッピングでは、お見せしたようなドキュメント型を必ず定義すべきです。実際の DTD は、上記の URL の hibernate-x.x.x/src/org/hibernate
ディレクトリ、または hibernate.jar
内にあります。 Hibernate は常に、そのクラスパス内で DTD を探し始めます。インターネットにある DTD ファイルを探そうとしたなら、クラスパスの内容を見て、 DTD 宣言を確認してください。
前述したように、 Hibernate はまずクラスパス内で DTD を解決しようとします。 org.xml.sax.EntityResolver
のカスタム実装を XML ファイルを読み込むための SAXReader に登録することによって、 DTD を解決します。このカスタムの EntityResolver
は2つの異なるシステム ID 名前空間を認識します。
hibernate namespace
は、リゾルバが http://hibernate.sourceforge.net/
で始まるシステム ID に到達したときに認識されます。そしてリゾルバは、 Hibernate のクラスをロードしたクラスローダを用いて、これらのエンティティを解決しようとします。
user namespace
は、リゾルバが URL プロトコルの classpath://
を使ったシステム ID に到達したときに、認識されます。そしてリゾルバは、 (1) カレントスレッドのコンテキストクラスローダー、または (2) Hibernate のクラスをロードしたクラスローダを使って、これらのエンティティを解決しようとします。
下記は、ユーザー名前空間を使った例です:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC '-//Hibernate/Hibernate Mapping DTD 3.0//EN' 'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd' [
<!ENTITY version "3.5.6-Final">
<!ENTITY today "September 15, 2010">
<!ENTITY types SYSTEM "classpath://your/domain/types.xml">
]>
<hibernate-mapping package="your.domain">
<class name="MyEntity">
<id name="id" type="my-custom-id-type">
...
</id>
<class>
&types;
</hibernate-mapping>
Where types.xml
is a resource in the your.domain
package and contains a custom typedef.
この要素にはいくつかオプション属性があります。 schema
属性と catalog
属性は、このマッピングが参照するテーブルが、この属性によって指定されたスキーマと(または)カタログに属することを指定します。この属性が指定されると、テーブル名は与えられたスキーマ名とカタログ名で修飾されます。これらの属性が指定されていなければ、テーブル名は修飾されません。 default-cascade
属性は、 cascade
属性を指定していないプロパティやコレクションに、どのカスケードスタイルを割り当てるかを指定します。 auto-import
属性は、クエリ言語内で修飾されていないクラス名を、デフォルトで使えるようにします。
<hibernate-mapping schema="schemaName" catal
og="catalogName" defau
lt-cascade="cascade_style" defau
lt-access="field|property|ClassName" defau
lt-lazy="true|false" auto-
import="true|false" packa
ge="package.name" />
| |
| |
| |
| |
| |
| |
|
(修飾されていない)同じ名前の永続クラスが2つあるなら、 auto-import="false"
を設定すべきです。2つのクラスに"インポートされた"同じ名前を割り当てようとすると、 Hibernate は例外を送出します。
hibernate-mapping
要素は、最初の例で示したようにいくつかの永続 <class>
マッピングをネストできます。しかし、1つのマッピングファイルではただひとつの永続クラス(またはひとつのクラス階層)にマッピングするようにし、さらに永続スーパークラスの後で指定するべきでしょう(いくつかのツールはこのようなマッピングファイルを想定しています)。例えば次のようになります。: Cat.hbm.xml
, Dog.hbm.xml
, または継承を使うなら Animal.hbm.xml
。
class
要素を使って、永続クラスを宣言できます:
<class name="ClassName" table=
"tableName" discri
minator-value="discriminator_value" mutabl
e="true|false" schema
="owner" catalo
g="catalog" proxy=
"ProxyInterface" dynami
c-update="true|false" dynami
c-insert="true|false" select
-before-update="true|false" polymo
rphism="implicit|explicit" where=
"arbitrary sql where condition" persis
ter="PersisterClass" batch-
size="N" optimi
stic-lock="none|version|dirty|all" lazy="(16)true|false" entity(17)-name="EntityName" check=(18)"arbitrary sql check condition" rowid=(19)"rowid" subsel(20)ect="SQL expression" abstra(21)ct="true|false" node="element-name" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
(16) |
|
(17) |
|
(18) |
|
(19) |
|
(20) |
|
(21) |
|
永続クラスの名前にインターフェースを指定してもまったく問題ありません。そのときは <subclass>
要素を使って、そのインターフェースを実装するクラスを定義してください。 static な内部クラスでも永続化できます。そのときは標準形式、例えば eg.Foo$Bar
を使ってクラス名を指定してください。
mutable="false"
指定をした不変クラスは、アプリケーションによる更新や削除が出来ないことがあります。これにより、 Hibernate がパフォーマンスを少し改善します。
オプションの proxy
属性により、クラスの永続インスタンスの遅延初期化が可能になります。 Hibernate は最初に、指定したインターフェースを実装した CGLIB プロキシを返します。実際の永続オブジェクトはプロキシのメソッドを呼び出すときにロードします。以下の「遅延初期化のためのプロキシ」を参照してください。
暗黙的 ポリモーフィズムとは、次の二つを意味しています。一つはクラスのインスタンスが、スーパークラスや実装したインターフェース、またそのクラスを指定するクエリによって返されることで、もう一つはそのクラスのサブクラスのインスタンスが、そのクラス自身を指定したクエリによって返されることです。また、 明示的 ポリモーフィズムとは、次の二つを意味しています。一つはクラスのインスタンスが、そのクラスを明示的に指定したクエリによってのみ返されることで、もう一つはクラスを指定したクエリが、 <class>
要素の中で <subclass>
や <joined-subclass>
とマッピングされているサブクラスのインスタンスだけを返すことです。ほとんどの用途ではデフォルトの polymorphism="implicit"
が適切です。明示的なポリモーフィズムは、2つの違ったクラスが同じテーブルにマッピングされているときに有用です (これによってテーブルカラムのサブセットを含む、「軽量な」クラスが可能になります)。
persister
属性を指定することで、クラスの永続化戦略をカスタマイズできます。例えば org.hibernate.persister.EntityPersister
自身のサブクラスを指定したり、また例えばストアドプロシージャコール、フラットファイルへシリアライズ、 LDAP などを通した永続性を実装する org.hibernate.persister.ClassPersister
インターフェースの完全に新しい実装を提供できます。簡単な例として org.hibernate.test.CustomPersister
を参照してください(これは Hashtable
の「永続化」です)。
dynamic-update
と dynamic-insert
の設定はサブクラスに継承されません。そのため <subclass>
や <joined-subclass>
要素を指定することも出来ます。これらの設定はパフォーマンスを向上させる事もありますが、落とすこともありますので、慎重に使用してください。
select-before-update
の使用は通常パフォーマンスを落とします。もし Session
へ分離インスタンスのグラフを再追加するなら、データベース更新のトリガを不必要に呼び出すのを避けるという点で、非常に有用です。
dynamic-update
を有効にすれば、楽観ロック戦略を選ぶことになります:
version
バージョン/タイムスタンプカラムをチェックします。
all
すべてのカラムをチェックします。
dirty
変更したカラムをチェックし、同時更新できるようにします。
none
楽観ロックを使用しません。
Hibernate で楽観的ロック戦略を使うなら、バージョン/タイムスタンプカラムを使うことを 非常に 強くお勧めします。楽観的ロックはパフォーマンスの観点からも最適であり、さらに分離インスタンスへの修正 (つまり Session.marge()
が使われるとき) を正確に扱うことのできる唯一の戦略でもあります。
Hibernate のマッピングにとってビューと普通のテーブルの間に違いはなく、データベースレベルでは透過的です(ただしビューを完全にはサポートしていない DBMS もあります。特に、更新のあるビューに対してはそうです)。ビューを使いたくても、データベースで作成できないことがあります(例えば、レガシースキーマの場合)。この場合には、不変かつ読み取り専用のエンティティに与えられた SQL の副問合せ文をマップできます:
<class name="Summary">
<subselect>
select item.name, max(bid.amount), count(*)
from item
join bid on bid.item_id = item.id
group by item.name
</subselect>
<synchronize table="item"/>
<synchronize table="bid"/>
<id name="name"/>
...
</class
>
テーブルをこのエンティティと同期するように定義してください。オートフラッシュが確実に起こるように、また導出エンティティに対するクエリが古いデータを返さないようにするためです。 <subselect>
は属性とネストしたマッピング属性のどちらでも利用できます。
マップされたクラスはデータベーステーブルの主キーカラムを定義 しなければなりません 。ほとんどのクラスにはインスタンスのユニークな識別子を保持する JavaBeans スタイルのプロパティも持っています。 <id>
要素は、そのプロパティから主キーカラムへのマッピングを定義します。
<id name="propertyName" type="
typename" column
="column_name" unsave
d-value="null|any|none|undefined|id_value" access
="field|property|ClassName"> node="element-name|@attribute-name|element/@attribute|." <generator class="generatorClass"/> </id >
| |
| |
| |
| |
|
name
属性がなければ、クラスには識別子プロパティがないものとみなされます。
unsaved-value
属性は Hibernate3 ではほとんどの場合、必要ではありません。
複合キーを持つレガシーデータにアクセスできるように、 <composite-id>
という代替のマッピング定義があります。しかし他の用途への使用は全くおすすめできません。
オプションの <generator>
子要素は、永続クラスのインスタンスのユニークな識別子を生成するために使う、 Java クラスを指定します。ジェネレータインスタンスの設定、もしくは初期化にパラメータが必要であれば、 <param>
要素を使って渡すことができます。
<id name="id" type="long" column="cat_id">
<generator class="org.hibernate.id.TableHiLoGenerator">
<param name="table"
>uid_table</param>
<param name="column"
>next_hi_value_column</param>
</generator>
</id
>
すべてのジェネレータは、 org.hibernate.id.IdentifierGenerator
インターフェースを実装します。これはとても単純なインターフェースなので、特別な実装を独自に用意するアプリケーションもあるかもしれません。しかし Hibernate は組み込みの実装をいくつも用意しています。組み込みのジェネレータには以下のショートカット名があります:
increment
long
, short
, int
型の識別子を生成します。これらは他のプロセスが同じテーブルにデータを挿入しないときだけユニークです。 クラスタ内では使わないでください 。
identity
DB2, MySQL, MS SQL Server, Sybase, HypersonicSQL の識別子カラムをサポートします。返される識別子の型は long
, short
, int
のいずれかです。
sequence
DB2, PostgreSQL, Oracle, SAP DB, McKoi のシーケンスや、 Interbase のジェネレータを使用します。返される識別子の型は long
, short
, int
のいずれかです。
hilo
long
, short
, int
型の識別子を効率的に生成する hi/lo アルゴリズムを使います。 hi 値のソースとして、テーブルとカラムを与えます(デフォルトではそれぞれ hibernate_unique_key
と next_hi
)。 hi/lo アルゴリズムは特定のデータベースに対してのみユニークな識別子を生成します。
seqhilo
long
, short
, int
型の識別子を効率的に生成する hi/lo アルゴリズムを使います。指定されたデータベースシーケンスを与えます。
uuid
( IP アドレスが使用される)ネットワーク内でユニークな文字列型の識別子を生成するために、 128 ビットの UUID アルゴリズムを使用します。 UUID は長さ 32 の 16 進数字の文字列としてエンコードされます。
guid
MS SQL サーバーと MySQL でデータベースが生成する GUID 文字列を使用します。
native
使用するデータベースの性能により identity
、 sequence
、 hilo
のいずれかが選ばれます。
assigned
save()
が呼ばれる前に、アプリケーションがオブジェクトに識別子を代入できるようにします。 <generator>
要素が指定されていなければ、これがデフォルトの戦略になります。
select
あるユニークキーによる行の選択と主キーの値の復元により、データベーストリガが割り当てた主キーを取得します。
foreign
他の関連オブジェクトの識別子を使います。普通は、 <one-to-one>
主キー関連と組み合わせて使います。
sequence-identity
実際の値の生成のためにデータベースシーケンスを使用する特別なシーケンス生成戦略ですが、 JDBC3 getGeneratedKeys と結びついて、 INSERT 文の実行の一部として生成された識別子の値を実際に返します。この戦略は JDK 1.4 を対象とする Oracle 10g のドライバでサポートされていることが知られています。これらの INSERT 文でのコメントは Oracle のドライバのバグにより無効にされていることに注意してください。
hilo
と seqhilo
ジェネレータは、識別子生成の代表的なアプローチである hi/lo アルゴリズムの2つの代替実装を提供します。1番目の実装は、次回に利用される "hi" 値を保持する「特別な」データベーステーブルを必要とします。2番目の実装は、 Oracle スタイルのシーケンスを使います(サポートされている場合)。
<id name="id" type="long" column="cat_id">
<generator class="hilo">
<param name="table"
>hi_value</param>
<param name="column"
>next_value</param>
<param name="max_lo"
>100</param>
</generator>
</id
>
<id name="id" type="long" column="cat_id">
<generator class="seqhilo">
<param name="sequence"
>hi_value</param>
<param name="max_lo"
>100</param>
</generator>
</id
>
残念ながら Hibernate への独自の Connection
を提供するときには、 hilo
を使えません。 Hibernate が JTA でリストされている接続を取得するためにアプリケーションサーバーのデータソースを使用しているときには、 hibernate.transaction.manager_lookup_class
を適切に設定しなければなりません。
UUID には以下のものが含まれます: IP アドレス、 JVM のスタートアップタイム(4分の1秒の正確さ)、システム時間、( JVM に対してユニークな)カウンタ値。 Java コードから MAC アドレスやメモリアドレスを取得することはできないので、 JNI が使えないときの最良の方法です。
識別子カラムをサポートしているデータベース(DB2, MySQL, Sybase, MS SQL)では、 identity
キー生成が使えます。シーケンスをサポートするデータベース(DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB)では、 sequence
スタイルのキー生成が使えます。どちらの戦略も、新しいオブジェクトを挿入するために、 SQL クエリを2つ必要とします。
<id name="id" type="long" column="person_id">
<generator class="sequence">
<param name="sequence"
>person_id_sequence</param>
</generator>
</id
>
<id name="id" type="long" column="person_id" unsaved-value="0">
<generator class="identity"/>
</id
>
クロスプラットフォームの開発では、native
戦略は identity
、 sequence
、 hilo
戦略の中から1つを選択しますが、これは使用しているデータベースの能力に依存します。
アプリケーションに識別子を割り当てさせたいのであれば( Hibernate が生成するものではなく)、 assigned
ジェネレータを使うことができます。この特別なジェネレータは、すでにオブジェクトの識別子プロパティに代入された値を識別子に使います。このジェネレータは主キーが代理キーの代わりに自然キーである場合に使用します。 <generator>
要素を指定しない場合のデフォルトの動作になります。
assigned
ジェネレータを選択すると、 Hibernate は unsaved-value="undefined"
を使います。そして、バージョンやタイムスタンプのプロパティがない場合や Interceptor.isUnsaved()
を定義しなかった場合には、インスタンスが一時的(transient)なものであるのか、またはセッションから分離(detached)したものかどうかを決めるために、データベースを調べます。
レガシースキーマのためにのみ指定します( Hibernate はトリガを使って DDL を生成しません)。
<id name="id" type="long" column="person_id">
<generator class="select">
<param name="key"
>socialSecurityNumber</param>
</generator>
</id
>
上記の例の中で、クラスで自然キーとして定義された socialSecurityNumber
という名前のユニークな値のプロパティと、値がトリガにより生成される person_id
という名前の代理キーがあります。
Starting with release 3.2.3, there are 2 new generators which represent a re-thinking of 2 different aspects of identifier generation. The first aspect is database portability; the second is optimization Optimization means that you do not have to query the database for every request for a new identifier value. These two new generators are intended to take the place of some of the named generators described above, starting in 3.3.x. However, they are included in the current releases and can be referenced by FQN.
The first of these new generators is org.hibernate.id.enhanced.SequenceStyleGenerator
which is intended, firstly, as a replacement for the sequence
generator and, secondly, as a better portability generator than native
. This is because native
generally chooses between identity
and sequence
which have largely different semantics that can cause subtle issues in applications eyeing portability. org.hibernate.id.enhanced.SequenceStyleGenerator
, however, achieves portability in a different manner. It chooses between a table or a sequence in the database to store its incrementing values, depending on the capabilities of the dialect being used. The difference between this and native
is that table-based and sequence-based storage have the same exact semantic. In fact, sequences are exactly what Hibernate tries to emulate with its table-based generators. This generator has a number of configuration parameters:
sequence_name
(optional, defaults to hibernate_sequence
): the name of the sequence or table to be used.
initial_value
(optional, defaults to 1
): the initial value to be retrieved from the sequence/table. In sequence creation terms, this is analogous to the clause typically named "STARTS WITH".
increment_size
(optional - defaults to 1
): the value by which subsequent calls to the sequence/table should differ. In sequence creation terms, this is analogous to the clause typically named "INCREMENT BY".
force_table_use
(optional - defaults to false
): should we force the use of a table as the backing structure even though the dialect might support sequence?
value_column
(optional - defaults to next_val
): only relevant for table structures, it is the name of the column on the table which is used to hold the value.
optimizer
(optional - defaults to none
): See 「Identifier generator optimization」
The second of these new generators is org.hibernate.id.enhanced.TableGenerator
, which is intended, firstly, as a replacement for the table
generator, even though it actually functions much more like org.hibernate.id.MultipleHiLoPerTableGenerator
, and secondly, as a re-implementation of org.hibernate.id.MultipleHiLoPerTableGenerator
that utilizes the notion of pluggable optimizers. Essentially this generator defines a table capable of holding a number of different increment values simultaneously by using multiple distinctly keyed rows. This generator has a number of configuration parameters:
table_name
(optional - defaults to hibernate_sequences
): the name of the table to be used.
value_column_name
(optional - defaults to next_val
): the name of the column on the table that is used to hold the value.
segment_column_name
(optional - defaults to sequence_name
): the name of the column on the table that is used to hold the "segment key". This is the value which identifies which increment value to use.
segment_value
(optional - defaults to default
): The "segment key" value for the segment from which we want to pull increment values for this generator.
segment_value_length
(optional - defaults to 255
): Used for schema generation; the column size to create this segment key column.
initial_value
(optional - defaults to 1
): The initial value to be retrieved from the table.
increment_size
(optional - defaults to 1
): The value by which subsequent calls to the table should differ.
optimizer
(optional - defaults to ): See 「Identifier generator optimization」
For identifier generators that store values in the database, it is inefficient for them to hit the database on each and every call to generate a new identifier value. Instead, you can group a bunch of them in memory and only hit the database when you have exhausted your in-memory value group. This is the role of the pluggable optimizers. Currently only the two enhanced generators (「Enhanced identifier generators」 support this operation.
none
(generally this is the default if no optimizer was specified): this will not perform any optimizations and hit the database for each and every request.
hilo
: applies a hi/lo algorithm around the database retrieved values. The values from the database for this optimizer are expected to be sequential. The values retrieved from the database structure for this optimizer indicates the "group number". The increment_size
is multiplied by that value in memory to define a group "hi value".
pooled
: as with the case of hilo
, this optimizer attempts to minimize the number of hits to the database. Here, however, we simply store the starting value for the "next group" into the database structure rather than a sequential value in combination with an in-memory grouping algorithm. Here, increment_size
refers to the values coming from the database.
<composite-id
name="propertyName"
class="ClassName"
mapped="true|false"
access="field|property|ClassName">
node="element-name|."
<key-property name="propertyName" type="typename" column="column_name"/>
<key-many-to-one name="propertyName" class="ClassName" column="column_name"/>
......
</composite-id
>
複合キーのあるテーブルに対し、識別子プロパティとしてクラスの複数のプロパティをマッピングすることができます。 <composite-id>
要素は、子要素として <key-property>
プロパティマッピングと <key-many-to-one>
マッピングを受け入れます。
<composite-id>
<key-property name="medicareNumber"/>
<key-property name="dependent"/>
</composite-id
>
複合識別子の等価性を実装するためには、永続クラスが equals()
と hashCode()
をオーバーライド しなければなりません 。 また Serializable
も実装しなければいけません。
残念ながら複合識別子のためのこの方法は、永続オブジェクトが自身の識別子であることを意味しています。オブジェクト自身を識別子とする以外に便利な「扱い方」はありません。複合キーに関連した永続状態を load()
出来るようになる前に、永続クラス自身をインスタンス化し、識別子プロパティを設定しなければなりません。 組み込みの 複合識別子と呼ばれるこのアプローチは、本格的なアプリケーションには向いていません。
2つ目の方法は マップされた 複合識別子と呼ばれるもので、 <composite-id>
エレメント内で指定した識別プロパティが永続クラスと分離した識別子クラスの両方に重複して存在します。
<composite-id class="MedicareId" mapped="true">
<key-property name="medicareNumber"/>
<key-property name="dependent"/>
</composite-id
>
この例では、複合識別子クラス( MedicareId
)とエンティティクラス自身の両方が、 medicareNumber
と dependent
という名前のプロパティを持ちます。識別子クラスは、 equals()
と hashCode()
をオーバライドし、 Serializable
を実装しなくてはなりません。この方法には、明らかにコードが重複するという不都合があります。
次の属性はマッピングした複合識別子を指定するために使用します:
mapped
(オプション、デフォルトは false
): マッピングした複合識別子が使用されることと、包含されたプロパティのマッピングが、エンティティクラスと複合識別子クラスの両方を参照することを示します。
class
(オプション、ただしマッピングした複合識別子には必須): 複合識別子として使用するクラス。
We will describe a third, even more convenient approach, where the composite identifier is implemented as a component class in 「複合識別子としてのコンポーネント」. The attributes described below apply only to this alternative approach:
name
(オプション、このアプローチでは必須): 複合識別子を保持するコンポーネントタイプのプロパティ(9章を参照してください)。
access
(オプション - デフォルトは property
): Hibernate がプロパティの値にアクセスするために使用すべき戦略。
class
(オプション - デフォルトはリフレクションにより決定されるプロパティの型): 複合識別子として使われるコンポーネントのクラス(次の節を見てください)。
この3つ目の方法は 識別子コンポーネント と呼び、ほとんどすべてのアプリケーションに対して推奨する方法です。
<discriminator>
要素は、 table-per-class-hierarchy マッピング戦略を使うポリモーフィックな永続化に必要であり、テーブルの識別カラムを定義します。識別カラムは、ある行に対して永続層がどのサブクラスをインスタンス化するかを伝えるマーカー値を含んでいます。以下のような型に制限されます: string
, character
, integer
, byte
, short
, boolean
, yes_no
, true_false
.
<discriminator column="discriminator_column" type="
discriminator_type" force=
"true|false" insert
="true|false" formul
a="arbitrary sql expression" />
| |
| |
| |
| |
|
識別カラムの実際の値は、 <class>
と <subclass>
要素の discriminator-value
属性で指定されます。
永続クラスへマッピングされない「余分な」識別値を持つ行がテーブルにあれば、(そのときに限り) force
属性は有効です。ただし、普通はそういうことはありません。
formula
属性を使うと、行の型を評価するために任意の SQL 式を宣言できます:
<discriminator
formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
type="integer"/>
<version>
要素はオプションであり、テーブルがバージョンデータを含むことを示します。これは ロングトランザクション を使うつもりなら、特に役立ちます(以下を参照してください)。
<version column="version_column" name="
propertyName" type="
typename" access
="field|property|ClassName" unsave
d-value="null|negative|undefined" genera
ted="never|always" insert
="true|false" node="element-name|@attribute-name|element/@attribute|." />
| |
| |
| |
| |
| |
| |
|
バージョン番号は Hibernate の long
、 integer
、 short
、 timestamp
、 calendar
型のいずれかです。
A version or timestamp property should never be null for a detached instance. Hibernate will detect any instance with a null version or timestamp as transient, irrespective of what other unsaved-value
strategies are specified. Declaring a nullable version or timestamp property is an easy way to avoid problems with transitive reattachment in Hibernate. It is especially useful for people using assigned identifiers or composite keys.
オプションの <timestamp>
要素は、テーブルがタイムスタンプデータを含むことを示します。これはバージョン付けの代わりの方法として用意されています。タイムスタンプはもともと楽観的ロックにおける安全性の低い実装です。しかしアプリケーションはタイムスタンプを異なる用途で使うこともあるかもしれません。
<timestamp column="timestamp_column" name="
propertyName" access
="field|property|ClassName" unsave
d-value="null|undefined" source
="vm|db" genera
ted="never|always" node="element-name|@attribute-name|element/@attribute|." />
| |
| |
| |
| |
| |
|
<timestamp>
は <version type="timestamp">
と等価であることに注意してください。 <timestamp source="db">
は <version type="dbtimestamp">
と等価であることに注意してください。
<property>
要素は、クラスの永続的な JavaBean スタイルのプロパティを定義します。
<property name="propertyName" column
="column_name" type="
typename" update
="true|false" insert
="true|false" formul
a="arbitrary SQL expression" access
="field|property|ClassName" lazy="
true|false" unique
="true|false" not-nu
ll="true|false" optimi
stic-lock="true|false" genera
ted="never|insert|always" node="element-name|@attribute-name|element/@attribute|." index="index_name" unique_key="unique_key_id" length="L" precision="P" scale="S" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
typename には以下の値が可能です:
Hibernate の基本型の名前(例 integer, string, character, date, timestamp, float, binary, serializable, object, blob
)。
デフォルトの基本型の Java クラス名 (例 int, float, char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob
)。
シリアライズ可能な Java クラスの名前。
カスタム型のクラス名(例 com.illflow.type.MyCustomType
)。
型を指定しなければ、 Hibernate は正しい Hibernate の型を推測するために、指定されたプロパティに対してリフレクションを使います。 Hibernate はルール2, 3, 4をその順序に使い、 getter プロパティの返り値のクラスの名前を解釈しようとします。しかしこれで常に十分であるとは限りません。場合によっては、 type
属性が必要な場合があります。 (例えば Hibernate.DATE
と Hibernate.TIMESTAMP
を区別するため、またはカスタム型を指定するためなどです。)
access
属性で、実行時に Hibernate がどのようにプロパティにアクセスするかを制御できます。デフォルトでは Hibernate はプロパティの get/set のペアをコールします。 access="field"
と指定すれば、 Hibernate はリフレクションを使い get/set のペアを介さずに、直接フィールドにアクセスします。インターフェース org.hibernate.property.PropertyAccessor
を実装するクラスを指定することで、プロパティへのアクセスに独自の戦略を指定することができます。
特に強力な特徴は生成プロパティです。これらのプロパティは当然読み取り専用であり、プロパティの値はロード時に計算されます。計算を SQL 式として宣言すると、このプロパティはインスタンスをロードする SQL クエリの SELECT
句のサブクエリに変換されます:
<property name="totalPrice"
formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
WHERE li.productId = p.productId
AND li.customerId = customerId
AND li.orderNumber = orderNumber )"/>
特定のカラム(例では customerId
がそれにあたります)のエイリアスを宣言することなく、エンティティ自身のテーブルを参照できることに注意してください。もし属性を使用したくなければ、ネストした <formula>
マッピング要素を使えることにも注意してください。
他の永続クラスへの通常の関連は many-to-one
要素を使って定義します。リレーショナルモデルは多対一関連です。つまりあるテーブルの外部キーは、ターゲットとなるテーブルの主キーカラムを参照しています。
<many-to-one name="propertyName" column
="column_name" class=
"ClassName" cascad
e="cascade_style" fetch=
"join|select" update
="true|false" insert
="true|false" proper
ty-ref="propertyNameFromAssociatedClass" access
="field|property|ClassName" unique
="true|false" not-nu
ll="true|false" optimi
stic-lock="true|false" lazy="
proxy|no-proxy|false" not-fo
und="ignore|exception" entity
-name="EntityName" formul
a="arbitrary SQL expression" node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" index="index_name" unique_key="unique_key_id" foreign-key="foreign_key_name" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
Setting a value of the cascade
attribute to any meaningful value other than none
will propagate certain operations to the associated object. The meaningful values are divided into three categories. First, basic operations, which include: persist, merge, delete, save-update, evict, replicate, lock and refresh
; second, special values: delete-orphan
; and third, all
comma-separated combinations of operation names: cascade="persist,merge,evict"
or cascade="all,delete-orphan"
. See 「連鎖的な永続化」 for a full explanation. Note that single valued, many-to-one and one-to-one, associations do not support orphan delete.
典型的な many-to-one
宣言は次のようにシンプルです。:
<many-to-one name="product" class="Product" column="PRODUCT_ID"/>
property-ref
属性は、外部キーが関連付けられたテーブルの、主キーでないユニークキーを参照しているレガシーデータをマップするためにだけ使うべきです。これは醜いリレーショナルモデルです。例えば Product
クラスが、主キーでないユニークなシリアルナンバーを持っていると仮定してみてください。( unique
属性は SchemaExport ツールを使った Hibernate の DDL 生成を制御します。)
<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>
以下のように OrderItem
に対してマッピングを使えます:
<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>
しかし、これは決して推奨できません。
参照したユニークキーが、関連するエンティティの多数のプロパティから構成される場合、指定した <properties>
要素内で、参照するプロパティをマッピングするべきです。
もし参照したユニークキーがコンポーネントのプロパティである場合は、プロパティのパスを指定できます:
<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>
他の永続クラスへの一対一関連は、one-to-one
要素で定義します。
<one-to-one name="propertyName" class=
"ClassName" cascad
e="cascade_style" constr
ained="true|false" fetch=
"join|select" proper
ty-ref="propertyNameFromAssociatedClass" access
="field|property|ClassName" formul
a="any SQL expression" lazy="
proxy|no-proxy|false" entity
-name="EntityName" node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" foreign-key="foreign_key_name" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
一対一関連には2種類あります:
主キー関連
ユニーク外部キー関連
主キー関連には、特別なテーブルカラムは必要ありません。もし2つの行が関連により関係していれば、2つのテーブルは同じ主キーの値を共有します。そのため2つのオブジェクトを主キー関連によって関連付けたいのであれば、確実に同じ識別子の値を代入しなければなりません。
主キー関連を行うためには、以下のマッピングを Employee
と Person
のそれぞれに追加してください。
<one-to-one name="person" class="Person"/>
<one-to-one name="employee" class="Employee" constrained="true"/>
ここで、 PERSON と EMPLOYEE テーブルの関係する行の主キーが同じであることを確実にしなければいけません。ここでは、 foreign
という特殊な Hibernate 識別子生成戦略を使います:
<class name="person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="foreign">
<param name="property"
>employee</param>
</generator>
</id>
...
<one-to-one name="employee"
class="Employee"
constrained="true"/>
</class
>
Employee
インスタンスが、 Person
の employee
プロパティで参照されるように、新しくセーブされた Person
のインスタンスには同じ主キーの値が代入されます。新しくセーブする Person
インスタンスは、その Person
の employee
プロパティが参照する Employee
インスタンスとして同じ主キーが割り当てられます。
もう1つの方法として、 Employee
から Person
へのユニーク制約を使った外部キー関連は以下のように表現されます:
<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>
そしてこの関連は、以下の記述を Person
のマッピングに追加することで双方向にすることができます:
<one-to-one name="employee" class="Employee" property-ref="person"/>
<natural-id mutable="true|false"/>
<property ... />
<many-to-one ... />
......
</natural-id
>
主キーとして代理キーの使用を推奨しますが、すべてのエンティティに対して自然キーを識別するようにすべきです。自然キーはユニークかつ非 null な一つのプロパティ、またはプロパティの連結です。不変であればさらに良いです。 <natural-id>
要素内で自然キーのプロパティをマッピングします。 Hibernate は必然的にユニークかつ null 値を許可する制約を生成し、こうしてマッピングはより自己記述的になります。
エンティティの自然キープロパティの比較には、 equals()
と hashCode()
の実装を強くお勧めします。
このマッピングは自然主キーを使ったエンティティでの使用を意図していません。
mutable
(オプション、 デフォルトは false
): デフォルトでは、自然識別子プロパティは不変(定数)と想定されています。
<component>
要素は、子オブジェクトのプロパティを親クラスのテーブルのカラムへマッピングします。コンポーネントは自分のプロパティ、コンポーネント、コレクションの順に定義できます。以下の「コンポーネント」を見てください。
<component name="propertyName" class=
"className" insert
="true|false" update
="true|false" access
="field|property|ClassName" lazy="
true|false" optimi
stic-lock="true|false" unique
="true|false" node="element-name|." > <property ...../> <many-to-one .... /> ........ </component >
| |
| |
| |
| |
| |
| |
| |
|
子の <property>
タグで、子のクラスのプロパティをテーブルカラムにマッピングします。
<component>
要素は、親エンティティへ戻る参照として、コンポーネントのクラスのプロパティをマッピングする <parent>
サブ要素を許可します。
The <dynamic-component>
element allows a Map
to be mapped as a component, where the property names refer to keys of the map. See 「動的コンポーネント」 for more information.
<properties>
要素はクラスのプロパティの指定された、論理的なグルーピングを可能にします。この構造の最も重要な使用方法は、 property-ref
のターゲットになるプロパティの結合を許可することです。それはまた、複数カラムのユニーク制約を定義する簡単な方法でもあります。
<properties name="logicalName" insert
="true|false" update
="true|false" optimi
stic-lock="true|false" unique
="true|false" > <property ...../> <many-to-one .... /> ........ </properties >
| |
| |
| |
| |
|
例えば、もし以下のような <properties>
マッピングがあった場合:
<class name="Person">
<id name="personNumber"/>
...
<properties name="name"
unique="true" update="false">
<property name="firstName"/>
<property name="initial"/>
<property name="lastName"/>
</properties>
</class
>
主キーの代わりに Person
テーブルのユニークキーへの参照を持つ、レガシーデータの関連を持つかもしれません。:
<many-to-one name="person"
class="Person" property-ref="name">
<column name="firstName"/>
<column name="initial"/>
<column name="lastName"/>
</many-to-one
>
しかし、このようなレガシーデータマッピングのコンテキスト外への使用は推奨しません。
最後にポリモーフィックな永続化には、ルートの永続クラスの各サブクラスの定義が必要です。 table-per-class-hierarchy マッピング戦略では、 <subclass>
定義が使われます。
<subclass name="ClassName" discri
minator-value="discriminator_value" proxy=
"ProxyInterface" lazy="
true|false" dynamic-update="true|false" dynamic-insert="true|false" entity-name="EntityName" node="element-name" extends="SuperclassName"> <property .... /> ..... </subclass >
| |
| |
| |
|
各サブクラスでは、永続プロパティとサブクラスを定義します。 <version>
と <id>
プロパティは、ルートクラスから継承されると仮定されます。階層構造におけるサブクラスは、ユニークな discriminator-value
を定義しなければなりません。 none が指定されると、完全修飾された Java クラス名が使われます。
For information about inheritance mappings see 9章継承マッピング.
もう1つの方法として、各サブクラスを自身のテーブルへマッピングすることができます (table-per-subclass mapping strategy)。継承した状態はスーパークラスのテーブルを使った結合で検索します。 <joined-subclass>
要素を使用します。
<joined-subclass name="ClassName" table=
"tablename" proxy=
"ProxyInterface" lazy="
true|false" dynamic-update="true|false" dynamic-insert="true|false" schema="schema" catalog="catalog" extends="SuperclassName" persister="ClassName" subselect="SQL expression" entity-name="EntityName" node="element-name"> <key .... > <property .... /> ..... </joined-subclass >
| |
| |
| |
|
このマッピング戦略には、識別カラムは必要ありません。しかし各サブクラスは <key>
要素を使い、オブジェクト識別子を保持するテーブルカラムを定義しなければなりません。この章の初めのマッピングは以下のように書き直せます:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="eg">
<class name="Cat" table="CATS">
<id name="id" column="uid" type="long">
<generator class="hilo"/>
</id>
<property name="birthdate" type="date"/>
<property name="color" not-null="true"/>
<property name="sex" not-null="true"/>
<property name="weight"/>
<many-to-one name="mate"/>
<set name="kittens">
<key column="MOTHER"/>
<one-to-many class="Cat"/>
</set>
<joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
<key column="CAT"/>
<property name="name" type="string"/>
</joined-subclass>
</class>
<class name="eg.Dog">
<!-- mapping for Dog could go here -->
</class>
</hibernate-mapping
>
For information about inheritance mappings see 9章継承マッピング.
3つ目の選択肢は、継承階層の具象クラスのみをテーブルにマッピングすることです (the table-per-concrete-class 戦略)。それぞれのテーブルは継承の状態を含めすべてのクラスの永続状態を定義します。 Hibernate ではその様な継承階層が必ずしも必要ではありません。単純にそれぞれのクラスを、別々の <class>
宣言を使ってマッピングすることができます。しかしポリモーフィックな関連 (例えば階層のスーパークラスへの関連) を使いたいなら、 <union-subclass>
マッピングを使う必要があります。
<union-subclass name="ClassName" table=
"tablename" proxy=
"ProxyInterface" lazy="
true|false" dynamic-update="true|false" dynamic-insert="true|false" schema="schema" catalog="catalog" extends="SuperclassName" abstract="true|false" persister="ClassName" subselect="SQL expression" entity-name="EntityName" node="element-name"> <property .... /> ..... </union-subclass >
| |
| |
| |
|
このマッピング戦略では識別カラムやキーカラムは必要ありません。
For information about inheritance mappings see 9章継承マッピング.
テーブル間に一対一の関係があるとき、 <join>
要素を使うことで、1つのクラスのプロパティをいくつものテーブルにマッピングすることができます。
<join table="tablename" schema
="owner" catalo
g="catalog" fetch=
"join|select" invers
e="true|false" option
al="true|false"> <key ... /> <property ... /> ... </join >
| |
| |
| |
| |
| |
|
例えば人のアドレスの情報を分離したテーブルにマッピングすることが可能です (すべてのプロパティに対して値型のセマンティクスを保持します):
<class name="Person"
table="PERSON">
<id name="id" column="PERSON_ID"
>...</id>
<join table="ADDRESS">
<key column="ADDRESS_ID"/>
<property name="address"/>
<property name="zip"/>
<property name="country"/>
</join>
...
この特徴はしばしばレガシーデータモデルに対してのみ有用ですが、クラスよりも少ないテーブルと、きめの細かいドメインモデルを推奨します。しかし後で説明するように、1つのクラス階層で継承のマッピング戦略を切り替える時には有用です。
今まで何度か <key>
要素が出てきました。この要素は新しいテーブルへの結合を定義したり、結合テーブルで外部キーを定義したりする親要素のどこにでも現れ、オリジナルテーブルの主キーを参照します。
<key column="columnname" on-del
ete="noaction|cascade" proper
ty-ref="propertyName" not-nu
ll="true|false" update
="true|false" unique
="true|false" />
| |
| |
| |
| |
| |
|
削除のパフォーマンスが重要であるシステムには、すべてのキーを on-delete="cascade"
と定義することを推奨します。そうすることで Hibernate は、 DELETE
文を毎回発行する代わりに、データベースレベルの ON CASCADE DELETE
制約を使用します。この特徴はバージョン付けられたデータに対する Hibernate の通常の楽観的ロック戦略を無視するということに注意してください。
not-null
と update
属性は、単方向一対多関連の時には有用です。単方向一対多関連を null を許容しない外部キーにマッピングするときは、 <key not-null="true">
を使ってキーカラムを宣言 しなくてはなりません 。
column
属性を記述できる任意のマッピング要素はまた、 <column>
サブ要素も記述できます。同様に <formula>
も formula
属性の代替手段です。
<column
name="column_name"
length="N"
precision="N"
scale="N"
not-null="true|false"
unique="true|false"
unique-key="multicolumn_unique_key_name"
index="index_name"
sql-type="sql_type_name"
check="SQL expression"
default="SQL expression"
read="SQL expression"
write="SQL expression"/>
<formula
>SQL expression</formula
>
Most of the attributes on column
provide a means of tailoring the DDL during automatic schema generation. The read
and write
attributes allow you to specify custom SQL that Hibernate will use to access the column's value. For more on this, see the discussion of column read and write expressions.
The column
and formula
elements can even be combined within the same property or association mapping to express, for example, exotic join conditions.
<many-to-one name="homeAddress" class="Address"
insert="false" update="false">
<column name="person_id" not-null="true" length="10"/>
<formula
>'MAILING'</formula>
</many-to-one
>
アプリケーションに同じ名前の2つの永続クラスがあり、 Hibernate クエリで完全修飾された(パッケージの)名前を指定したくないと仮定します。そのような場合は auto-import="true"
に頼らず、クラスが「インポート」されたものであると明示できます。明示的にマッピングされていないクラスやインターフェースでさえもインポートできます。
<import class="java.lang.Object" rename="Universe"/>
<import class="ClassName" rename
="ShortName" />
| |
|
プロパティマッピングにはさらにもう1つの型があります。 <any>
マッピング要素は、複数のテーブルからクラスへのポリモーフィックな関連を定義します。この型のマッピングには必ず複数のカラムが必要です。1番目のカラムは関連エンティティの型を保持します。残りのカラムは識別子を保持します。この種類の関連には外部キー制約を指定することはできません。そのためこれは最も使われることのない(ポリモーフィックな)関連のマッピング方法です。非常に特別な場合(例えば、検査ログやユーザーセッションデータなど)に限って、これを使うべきです。
meta-type
により、アプリケーションはカスタム型を指定できます。このカスタム型はデータベースカラムの値を、 id-type
で指定した型の識別子プロパティを持った永続クラスへマッピングします。 meta-type の値からクラス名へのマッピングを指定しなければなりません。
<any name="being" id-type="long" meta-type="string">
<meta-value value="TBL_ANIMAL" class="Animal"/>
<meta-value value="TBL_HUMAN" class="Human"/>
<meta-value value="TBL_ALIEN" class="Alien"/>
<column name="table_name"/>
<column name="id"/>
</any
>
<any name="propertyName" id-typ
e="idtypename" meta-t
ype="metatypename" cascad
e="cascade_style" access
="field|property|ClassName" optimi
stic-lock="true|false" > <meta-value ... /> <meta-value ... /> ..... <column .... /> <column .... /> ..... </any >
| |
| |
| |
| |
| |
|
In relation to the persistence service, Java language-level objects are classified into two groups:
エンティティ はエンティティへの参照を保持する、他のすべてのオブジェクトから独立して存在します。参照されないオブジェクトがガベージコレクトされてしまう性質を持つ通常の Java モデルと、これを比べてみてください。(親エンティティから子へ、セーブと削除が カスケード されうることを除いて)エンティティは明示的にセーブまたは削除されなければなりません。これは到達可能性によるオブジェクト永続化の ODMG モデルとは異なっています。大規模なシステムでアプリケーションオブジェクトが普通どのように使われるかにより密接に対応します。エンティティは循環と参照の共有をサポートします。またそれらはバージョン付けすることもできます。
エンティティの永続状態は他のエンティティや 値 型のインスタンスへの参照から構成されます。値はプリミティブ、コレクション (コレクションの内部ではなく)、コンポーネント、不変オブジェクトです。エンティティとは違い、値は(特にコレクションとコンポーネントにおいて)、到達可能性による永続化や削除が 行われます 。値オブジェクト(とプリミティブ)は、包含するエンティティと一緒に永続化や削除が行われるので、それらを独立にバージョン付けすることはできません。値には独立したアイデンティティがないので、複数のエンティティやコレクションがこれを共有することはできません。
これまで「永続クラス」という言葉をエンティティの意味で使ってきました。これからもそうしていきます。厳密に言うと、永続状態を持つユーザー定義のクラスのすべてがエンティティというわけではありません。 コンポーネント は値のセマンティクスを持つユーザー定義クラスです。 java.lang.String
型のプロパティもまた値のセマンティクスを持ちます。定義するなら、 JDK で提供されているすべての Java の型 (クラス) が値のセマンティクスを持つといえます。一方ユーザー定義型は、エンティティや値型のセマンティクスとともにマッピングできます。この決定はアプリケーション開発者次第です。そのクラスの1つのインスタンスへの共有参照は、ドメインモデル内のエンティティクラスに対する良いヒントになります。一方合成集約や集約は、通常値型へ変換されます。
本ドキュメントを通して、何度もこの概念を取り上げます。
Java 型のシステム (もしくは開発者が定義したエンティティと値型) を SQL /データベース型のシステムにマッピングすることは難しいです。 Hibernate は2つのシステムの架け橋を提供します。エンティティに対しては <class>
や <subclass>
などを使用します。値型に対しては <property>
や <component>
などを、通常 type
と共に使います。この属性の値は Hibernate の マッピング型 の名前です。 Hibernate は (標準 JDK の値型に対して) 多くの自由なマッピングを提供します。後で見るように、自身のマッピング型を記述し、同様にカスタムの変換戦略を実装することができます。
コレクションを除く組み込みの Hibernate の型はすべて、 null セマンティクスをサポートします。
組み込みの 基本的なマッピング型 は大まかに以下のように分けられます。
integer, long, short, float, double, character, byte, boolean, yes_no, true_false
Java のプリミティブやラッパークラスから適切な(ベンダー固有の) SQL カラム型への型マッピング。 boolean, yes_no
と true_false
は、すべて Java の boolean
または java.lang.Boolean
の代替エンコードです。
string
java.lang.String
から VARCHAR
(または Oracle の VARCHAR2
)への型マッピング。
date, time, timestamp
java.util.Date
とそのサブクラスから SQL 型の DATE
、 TIME
、 TIMESTAMP
(またはそれらと等価なもの) への型マッピング。
calendar, calendar_date
java.util.Calendar
から SQL 型 の「 TIMESTAMP
、 DATE
(またはそれらと等価なもの)への型マッピング。
big_decimal, big_integer
java.math.BigDecimal
と java.math.BigInteger
から NUMERIC
(または Oracle の NUMBER
)への型マッピング。
locale, timezone, currency
java.util.Locale
、 java.util.TimeZone
、 java.util.Currency
から VARCHAR
(または Oracle の VARCHAR2
)への型マッピング。 Locale
と Currency
のインスタンスは、それらの ISO コードにマッピングされます。 TimeZone
のインスタンスは、それらの ID
にマッピングされます。
class
java.lang.Class
から VARCHAR
(または Oracle の VARCHAR2
)への型マッピング。 Class
はその完全修飾された名前にマッピングされます。
binary
バイト配列は、適切な SQL のバイナリ型にマッピングされます。
text
長い Java 文字列は、 SQL の CLOB
または TEXT
型にマッピングされます。
serializable
シリアライズ可能な Java 型は、適切な SQL のバイナリ型にマッピングされます。デフォルトで基本型ではないシリアライズ可能な Java クラスやインターフェースの名前を指定することで、 Hibernate の型を serializable
とすることもできます。
clob, blob
JDBC クラス java.sql.Clob
と java.sql.Blob
に対する型マッピング。 blob や clob オブジェクトはトランザクションの外では再利用できないため、アプリケーションによっては不便かもしれません。(さらにはドライバサポートが一貫していません。)
imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date, imm_serializable, imm_binary
ほとんどの場合に可変である Java の型に対する型マッピング。 Hibernate は不変な Java の型に対しては最適化を行い、アプリケーションはそれを不変オブジェクトとして扱います。例えば imm_timestamp
としてマップしたインスタンスに対して、 Date.setTime()
を呼び出してはなりません。プロパティの値を変更しその変更を永続化するためには、アプリケーションはプロパティに対して新しい (同一でない) オブジェクトを割り当てなければなりません。
エンティティとコレクションのユニークな識別子は、 binary
、 blob
、 clob
を除く、どんな基本型でも構いません。(複合識別子でも構いません。以下を見てください。)
基本的な値型には、 org.hibernate.Hibernate
で定義された Type
定数がそれぞれあります。例えば、 Hibernate.STRING
は string
型を表現しています。
開発者が独自の値型を作成することは、比較的簡単です。例えば、 java.lang.BigInteger
型のプロパティを VARCHAR
カラムに永続化したいかもしれません。 Hibernate はこのための組み込み型を用意していません。しかしカスタム型は、プロパティ(またはコレクションの要素)を1つのテーブルカラムにマッピングするのに制限はありません。そのため例えば、 java.lang.String
型の getName()
/ setName()
Java プロパティを FIRST_NAME
、 INITIAL
、 SURNAME
カラムに永続化できます。
カスタム型を実装するには、 org.hibernate.UserType
または org.hibernate.CompositeUserType
を実装し、型の完全修飾された名前を使ってプロパティを定義します。どのような種類のものが可能かを調べるには、 org.hibernate.test.DoubleStringType
を確認してください。
<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
<column name="first_string"/>
<column name="second_string"/>
</property
>
<column>
タグで、プロパティを複数のカラムへマッピングできることに注目してください。
CompositeUserType
、 EnhancedUserType
、 UserCollectionType
、 UserVersionType
インターフェースは、より特殊な使用法に対してのサポートを提供します。
マッピングファイル内で UserType
へパラメータを提供できます。このためには、 UserType
は org.hibernate.usertype.ParameterizedType
を実装しなくてはなりません。カスタム型パラメータを提供するために、マッピングファイル内で <type>
要素を使用できます。
<property name="priority">
<type name="com.mycompany.usertypes.DefaultValueIntegerType">
<param name="default"
>0</param>
</type>
</property
>
UserType
は、引数として渡された Properties
オブジェクトから、 default
で指定したパラメータに対する値を検索することができます。
特定の UserType
を頻繁に使用するならば、短い名前を定義すると便利になるでしょう。 <typedef>
要素を使ってこのようなことが行えます。 Typedefs はカスタム型に名前を割り当てます。その型がパラメータを持つならば、パラメータのデフォルト値のリストを含むこともできます。
<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
<param name="default"
>0</param>
</typedef
>
<property name="priority" type="default_zero"/>
プロパティのマッピングで型パラメータを使うことで、 typedef で提供されたパラメータをその都度オーバーライドすることが可能です。
Even though Hibernate's rich range of built-in types and support for components means you will rarely need to use a custom type, it is considered good practice to use custom types for non-entity classes that occur frequently in your application. For example, a MonetaryAmount
class is a good candidate for a CompositeUserType
, even though it could be mapped as a component. One reason for this is abstraction. With a custom type, your mapping documents would be protected against changes to the way monetary values are represented.
ある永続クラスに、一つ以上のマッピングを提供することが出来ます。この場合、マッピングする2つのエンティティのインスタンスを明確にするために、 エンティティ名 を指定しなければなりません (デフォルトではエンティティ名はクラス名と同じです。)。 Hibernate では、永続オブジェクトを扱うとき、クエリを書き込むとき、指定されたエンティティへの関連をマッピングするときに、エンティティ名を指定しなければなりません。
<class name="Contract" table="Contracts" entity-name="CurrentContract"> ... <set name="history" inverse="true" order-by="effectiveEndDate desc"> <key column="currentContractId"/> <one-to-many entity-name="HistoricalContract"/> </set> </class> <class name="Contract" table="ContractHistory" entity-name="HistoricalContract"> ... <many-to-one name="currentContract" column="currentContractId" entity-name="CurrentContract"/> </class >
関連が class
の代わりに entity-name
を使って、どのように指定されるのかに注目してください。
マッピングドキュメントでテーブルやカラムの名前をバッククォートで囲むことで、 Hibernate で生成された SQL 中の識別子を引用させることができます。 Hibernate は SQL の Dialect
に対応する、正しい引用スタイルを使います(普通はダブルクォートですが、 SQL Server ではかぎ括弧、 MySQL ではバッククォートです)。
<class name="LineItem" table="`Line Item`">
<id name="id" column="`Item Id`"/><generator class="assigned"/></id>
<property name="itemNumber" column="`Item #`"/>
...
</class
>
XML の記述以外に、 Hibernate では O/R マッピングのメタデータを定義する代替方法があります。
多くの Hibernate ユーザーは XDoclet の @hibernate.tags
を使って、ソースコード内に直接マッピング情報を埋め込むことを好みます。これは厳密に言えば XDoclet の分野なので、本ドキュメントではこの方法を対象とはしません。しかし XDoclet を使った以下の Cat
マッピングの例を示します。
package eg;
import java.util.Set;
import java.util.Date;
/**
* @hibernate.class
* table="CATS"
*/
public class Cat {
private Long id; // identifier
private Date birthdate;
private Cat mother;
private Set kittens
private Color color;
private char sex;
private float weight;
/*
* @hibernate.id
* generator-class="native"
* column="CAT_ID"
*/
public Long getId() {
return id;
}
private void setId(Long id) {
this.id=id;
}
/**
* @hibernate.many-to-one
* column="PARENT_ID"
*/
public Cat getMother() {
return mother;
}
void setMother(Cat mother) {
this.mother = mother;
}
/**
* @hibernate.property
* column="BIRTH_DATE"
*/
public Date getBirthdate() {
return birthdate;
}
void setBirthdate(Date date) {
birthdate = date;
}
/**
* @hibernate.property
* column="WEIGHT"
*/
public float getWeight() {
return weight;
}
void setWeight(float weight) {
this.weight = weight;
}
/**
* @hibernate.property
* column="COLOR"
* not-null="true"
*/
public Color getColor() {
return color;
}
void setColor(Color color) {
this.color = color;
}
/**
* @hibernate.set
* inverse="true"
* order-by="BIRTH_DATE"
* @hibernate.collection-key
* column="PARENT_ID"
* @hibernate.collection-one-to-many
*/
public Set getKittens() {
return kittens;
}
void setKittens(Set kittens) {
this.kittens = kittens;
}
// addKitten not needed by Hibernate
public void addKitten(Cat kitten) {
kittens.add(kitten);
}
/**
* @hibernate.property
* column="SEX"
* not-null="true"
* update="false"
*/
public char getSex() {
return sex;
}
void setSex(char sex) {
this.sex=sex;
}
}
Hibernate のウェブサイトには、 XDoclet と Hibernate に関するサンプルが多数あります。
JDK5.0 ではタイプセーフかつコンパイル時にチェックできる、言語レベルの XDoclet スタイルのアノテーションを導入しました。このメカニズムは XDoclet のアノテーションよりも強力で、ツールや IDE も多くがサポートしています。例えば IntelliJ IDEA は、 JDK5.0 にアノテーションの自動補完と構文の強調表示をサポートしています。 EJB 仕様 (JSR-220) の新しいバージョンでは、エンティティ Bean に対する主要なメタデータメカニズムとして JDK5.0 のアノテーションを使用しています。 Hibernate3 では JSR-220 (永続化 API) の EntityManager
を実装し、メタデータマッピングに対するサポートは、別ダウンロードの Hibernate Annotations パッケージにより利用可能です。これは EJB3 (JSR-220) と Hibernate3 のメタデータをどちらもサポートしています。
以下は EJB のエンティティ Bean として注釈された POJO クラスの例です:
@Entity(access = AccessType.FIELD)
public class Customer implements Serializable {
@Id;
Long id;
String firstName;
String lastName;
Date birthday;
@Transient
Integer age;
@Embedded
private Address homeAddress;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="CUSTOMER_ID")
Set<Order
> orders;
// Getter/setter and business methods
}
JDK5.0 のアノテーション (と JSR-220) のサポートは進行中の作業であり、完全ではないことに注意してください。さらに詳しい情報は Hibernate のアノテーションモジュールを参照してください。
生成プロパティとは、データベースによって生成された値を持つプロパティです。通常、 Hibernate アプリケーションは、データベースが値を生成したプロパティを含むオブジェクトを リフレッシュ
する必要がありました。しかし、プロパティが生成されたということをマークすることで、アプリケーションはリフレッシュの責任を Hibernate に委譲します。基本的に、生成プロパティを持つと定義したエンティティに対して Hibernate が INSERT や UPDATE の SQL を発行した後すぐに、生成された値を読み込むための SELECT SQL が発行されます。
Properties marked as generated must additionally be non-insertable and non-updateable. Only versions, timestamps, and simple properties, can be marked as generated.
never
(デフォルト) - 与えられたプロパティの値は、データベースから生成されないことを意味します。
insert
: the given property value is generated on insert, but is not regenerated on subsequent updates. Properties like created-date fall into this category. Even though version and timestamp properties can be marked as generated, this option is not available.
always
- 挿入時も更新時もプロパティの値が生成されることを示します。
Hibernate allows you to customize the SQL it uses to read and write the values of columns mapped to simple properties. For example, if your database provides a set of data encryption functions, you can invoke them for individual columns like this:
<!-- XML : generated by JHighlight v1.0 (http://jhighlight.dev.java.net) --> <span class="xml_tag_symbols"><</span><span class="xml_tag_name">property</span><span class="xml_plain"> </span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">"creditCardNumber"</span><span class="xml_tag_symbols">></span><span class="xml_plain"></span><br /> <span class="xml_plain"> </span><span class="xml_tag_symbols"><</span><span class="xml_tag_name">column</span><span class="xml_plain"> </span><br /> <span class="xml_plain"> </span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">"credit_card_num"</span><span class="xml_plain"></span><br /> <span class="xml_plain"> </span><span class="xml_attribute_name">read</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">"decrypt(credit_card_num)"</span><span class="xml_plain"></span><br /> <span class="xml_plain"> </span><span class="xml_attribute_name">write</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">"encrypt(?)"</span><span class="xml_tag_symbols">/></span><span class="xml_plain"></span><br /> <span class="xml_tag_symbols"></</span><span class="xml_tag_name">property</span><span class="xml_plain"></span><br /> <span class="xml_tag_symbols">></span><span class="xml_plain"></span><br />
Hibernate applies the custom expressions automatically whenever the property is referenced in a query. This functionality is similar to a derived-property formula
with two differences:
The property is backed by one or more columns that are exported as part of automatic schema generation.
The property is read-write, not read-only.
The write
expression, if specified, must contain exactly one '?' placeholder for the value.
Hibernate のスキーマエボリューションツールと連動することで、任意のデータベースオブジェクト(トリガーやストアドプロシージャなど)の CREATE と DROP により、 Hibernate のマッピングファイル内のユーザースキーマをすべて定義することが出来ます。主にトリガやストアドプロシージャのようなデータベースオブジェクトを生成や削除することを意図していますが、実際には java.sql.Statement.execute()
メソッドによって実行できる任意の SQL コマンド(ALTER、INSERTなど)が実行できます。補助的なデータベースオブジェクトを定義するための、2つの基本的な方法があります。
1つ目の方法は、 CREATE と DROP コマンドをマッピングファイルの外に、明示的に記載することです:
<hibernate-mapping>
...
<database-object>
<create
>CREATE TRIGGER my_trigger ...</create>
<drop
>DROP TRIGGER my_trigger</drop>
</database-object>
</hibernate-mapping
>
2つ目の方法は、 CREATE と DROP コマンドの組み立て方を知っているカスタムクラスを提供することです。このカスタムクラスは org.hibernate.mapping.AuxiliaryDatabaseObject
インタフェースを実装しなければなりません。
<hibernate-mapping>
...
<database-object>
<definition class="MyTriggerDefinition"/>
</database-object>
</hibernate-mapping
>
さらに、あるデータベース方言が使用される時にだけ適用するといったように、データベースオブジェクトが使われるケースを限定できます。
<hibernate-mapping>
...
<database-object>
<definition class="MyTriggerDefinition"/>
<dialect-scope name="org.hibernate.dialect.Oracle9iDialect"/>
<dialect-scope name="org.hibernate.dialect.Oracle10gDialect"/>
</database-object>
</hibernate-mapping
>
製作著作 © 2004 Red Hat, Inc.