updated encoding to UTF-8

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14110 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2007-10-19 03:50:52 +00:00
parent 923ac2533f
commit dd2c283108
27 changed files with 5945 additions and 5901 deletions

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY versionNumber "3.3.0.alpha1">

View File

@ -1,13 +1,15 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="architecture">
<title>アーキテクチャ</title>
<title>アーキテクチャ</title>
<sect1 id="architecture-overview" revision="1">
<title>概観</title>
<title>概観</title>
<para>
Hibernateアーキテクチャの非常に高いレベルからのビュー
Hibernateアーキテクチャの非常に高いレベルからのビュー
</para>
<mediaobject>
@ -20,18 +22,18 @@
</mediaobject>
<para>
この図はHibernateが、アプリケーションに対して永続化サービス
(と永続オブジェクト)を提供するために、データベースと設定データを使うことを
示しています。
この図はHibernateが、アプリケーションに対して永続化サービス
(と永続オブジェクト)を提供するために、データベースと設定データを使うことを
示しています。
</para>
<para>
ここで実行時アーキテクチャのより詳細なビューをお見せしましょう。
あいにく、Hibernateは柔軟であり、いろいろなアプローチをサポートしています。
ここでは、2つの極端な例をお見せします。
「軽い」アーキテクチャでは、アプリケーションが自前のJDBCコネクションを用意し、
アプリケーション自身がトランザクションを管理します。
この方法は、Hibernate APIの最小限のサブセットを使います
ここで実行時アーキテクチャのより詳細なビューをお見せしましょう。
あいにく、Hibernateは柔軟であり、いろいろなアプローチをサポートしています。
ここでは、2つの極端な例をお見せします。
「軽い」アーキテクチャでは、アプリケーションが自前のJDBCコネクションを用意し、
アプリケーション自身がトランザクションを管理します。
この方法は、Hibernate APIの最小限のサブセットを使います
</para>
<mediaobject>
@ -44,8 +46,8 @@
</mediaobject>
<para>
「重い」アーキテクチャは、アプリケーションから、その下に位置するJDBCやJTAのAPIを
取り払って抽象化し、その詳細の面倒をHibernateに見させます。
「重い」アーキテクチャは、アプリケーションから、その下に位置するJDBCやJTAのAPIを
取り払って抽象化し、その詳細の面倒をHibernateに見させます。
</para>
<mediaobject>
@ -58,19 +60,19 @@
</mediaobject>
<para>
以下は、上の図に含まれるオブジェクトの定義です:
以下は、上の図に含まれるオブジェクトの定義です:
<variablelist spacing="compact">
<varlistentry>
<term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
<listitem>
<para>
1つのデータベースに対するコンパイルされたマッピングの
スレッドセーフな(更新不能の)キャッシュ。
<literal>Session</literal> のファクトリであり、
<literal>ConnectionProvider</literal> のクライアント。
オプションとして、プロセスまたはクラスタレベルにおいて、
トランザクション間で再利用可能なデータの(二次)キャッシュを持ちます。
1つのデータベースに対するコンパイルされたマッピングの
スレッドセーフな(更新不能の)キャッシュ。
<literal>Session</literal> のファクトリであり、
<literal>ConnectionProvider</literal> のクライアント。
オプションとして、プロセスまたはクラスタレベルにおいて、
トランザクション間で再利用可能なデータの(二次)キャッシュを持ちます。
</para>
</listitem>
</varlistentry>
@ -78,38 +80,38 @@
<term>Session (<literal>org.hibernate.Session</literal>)</term>
<listitem>
<para>
アプリケーションと永続ストアとの対話を表す、
シングルスレッドで短命のオブジェクト。
JDBCコネクションをラップします。
<literal>Transaction</literal> のファクトリです。
永続オブジェクトの必須の(一次)キャッシュを保持します。
このキャッシュはオブジェクトグラフをナビゲーションする時や、
識別子でオブジェクトを検索する時に使われます。
アプリケーションと永続ストアとの対話を表す、
シングルスレッドで短命のオブジェクト。
JDBCコネクションをラップします。
<literal>Transaction</literal> のファクトリです。
永続オブジェクトの必須の(一次)キャッシュを保持します。
このキャッシュはオブジェクトグラフをナビゲーションする時や、
識別子でオブジェクトを検索する時に使われます。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Persistent objects と Collections</term>
<term>Persistent objects と Collections</term>
<listitem>
<para>
永続化状態とビジネスメソッドを持つ、短命でシングルスレッドのオブジェクト。
これは通常のJavaBeans/POJOのこともありますが、特徴的なことは、
その時点でのただ1つの <literal>Session</literal> と関連していることです。
<literal>Session</literal> がクローズされるとすぐに、
それらは切り離されて他のアプリケーション層から自由に使うことができます。
(例えばデータ・トランスファ・オブジェクトとして、
プレゼンテーション層から、またはプレゼンテーション層へ直接使用できます。)
永続化状態とビジネスメソッドを持つ、短命でシングルスレッドのオブジェクト。
これは通常のJavaBeans/POJOのこともありますが、特徴的なことは、
その時点でのただ1つの <literal>Session</literal> と関連していることです。
<literal>Session</literal> がクローズされるとすぐに、
それらは切り離されて他のアプリケーション層から自由に使うことができます。
(例えばデータ・トランスファ・オブジェクトとして、
プレゼンテーション層から、またはプレゼンテーション層へ直接使用できます。)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Transient と detached な objects と Collections</term>
<term>Transient と detached な objects と Collections</term>
<listitem>
<para>
現時点では <literal>Session</literal> と関連していない、
永続クラスのインスタンス。
すでにアプリケーション側でインスタンス化されていて、まだ永続化されていないか、
クローズされた <literal>Session</literal> でインスタンス化されたかのどちらかです。
現時点では <literal>Session</literal> と関連していない、
永続クラスのインスタンス。
すでにアプリケーション側でインスタンス化されていて、まだ永続化されていないか、
クローズされた <literal>Session</literal> でインスタンス化されたかのどちらかです。
</para>
</listitem>
</varlistentry>
@ -117,13 +119,13 @@
<term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
<listitem>
<para>
(オプション)原子性を持つ作業単位(Unit of Work)を指定するために、アプリケーションが使用する、
シングルスレッドで短命なオブジェクト。
下に位置するJDBC、JTA、CORBAトランザクションからアプリケーションを抽象化します。
<literal>Session</literal> は、時には
いくつかの <literal>Transaction</literal> をまたがるかもしれません。
しかし、下の層のAPIを使うにせよ、 <literal>Transaction</literal> を使うにせよ、
トランザクション境界を設定することは、決してオプションではありません!。
(オプション)原子性を持つ作業単位(Unit of Work)を指定するために、アプリケーションが使用する、
シングルスレッドで短命なオブジェクト。
下に位置するJDBC、JTA、CORBAトランザクションからアプリケーションを抽象化します。
<literal>Session</literal> は、時には
いくつかの <literal>Transaction</literal> をまたがるかもしれません。
しかし、下の層のAPIを使うにせよ、 <literal>Transaction</literal> を使うにせよ、
トランザクション境界を設定することは、決してオプションではありません!。
</para>
</listitem>
</varlistentry>
@ -131,10 +133,10 @@
<term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
<listitem>
<para>
(オプション)JDBCコネクションとそのプールのファクトリ。
下の層に位置する <literal>Datasource</literal>
<literal>DriverManager</literal> からアプリケーションを抽象化します。
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
(オプション)JDBCコネクションとそのプールのファクトリ。
下の層に位置する <literal>Datasource</literal>
<literal>DriverManager</literal> からアプリケーションを抽象化します。
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
</para>
</listitem>
</varlistentry>
@ -142,8 +144,8 @@
<term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
<listitem>
<para>
(オプション) <literal>Transaction</literal> インスタンスのファクトリ。
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
(オプション) <literal>Transaction</literal> インスタンスのファクトリ。
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
</para>
</listitem>
</varlistentry>
@ -151,9 +153,9 @@
<term><emphasis>Extension Interfaces</emphasis></term>
<listitem>
<para>
Hibernateは、永続層の振る舞いをカスタマイズするために、
多くのオプション拡張インタフェースを用意しています。
詳細はAPIドキュメントを参照してください。
Hibernateは、永続層の振る舞いをカスタマイズするために、
多くのオプション拡張インタフェースを用意しています。
詳細はAPIドキュメントを参照してください。
</para>
</listitem>
</varlistentry>
@ -161,18 +163,18 @@
</para>
<para>
「軽い」アーキテクチャでは、アプリケーションは直接JTAやJDBCと対話するために、
<literal>Transaction</literal><literal>TransactionFactory</literal>
<literal>ConnectionProvider</literal> をバイパスします。
「軽い」アーキテクチャでは、アプリケーションは直接JTAやJDBCと対話するために、
<literal>Transaction</literal><literal>TransactionFactory</literal>
<literal>ConnectionProvider</literal> をバイパスします。
</para>
</sect1>
<sect1 id="architecture-states" revision="1">
<title>インスタンスの状態</title>
<title>インスタンスの状態</title>
<para>
永続クラスのインスタンスは、次の3つの異なる状態のどれかになります。
それは、 <emphasis>永続コンテキスト</emphasis> によって決まります。
Hibernateの <literal>Session</literal> オブジェクトが、永続コンテキストになります。
永続クラスのインスタンスは、次の3つの異なる状態のどれかになります。
それは、 <emphasis>永続コンテキスト</emphasis> によって決まります。
Hibernateの <literal>Session</literal> オブジェクトが、永続コンテキストになります。
</para>
<variablelist spacing="compact">
@ -180,9 +182,9 @@
<term>transient</term>
<listitem>
<para>
この状態のインスタンスは、現在もそして過去においても、
永続コンテキストに関連づいていません。また、永続ID主キーの値
持っていません。
この状態のインスタンスは、現在もそして過去においても、
永続コンテキストに関連づいていません。また、永続ID主キーの値
持っていません。
</para>
</listitem>
</varlistentry>
@ -190,12 +192,12 @@
<term>persistent</term>
<listitem>
<para>
この状態のインスタンスは、その時点で永続コンテキストに関連づいています。
また、永続ID主キーの値を持ち、
たいていはデータベースに対応する行を持っているでしょう。
個々の永続コンテキストのなかでは、永続IDが
JavaのIDオブジェクトのメモリ上の位置と同じであることを
Hibernateが <emphasis>保証</emphasis> します。
この状態のインスタンスは、その時点で永続コンテキストに関連づいています。
また、永続ID主キーの値を持ち、
たいていはデータベースに対応する行を持っているでしょう。
個々の永続コンテキストのなかでは、永続IDが
JavaのIDオブジェクトのメモリ上の位置と同じであることを
Hibernateが <emphasis>保証</emphasis> します。
</para>
</listitem>
</varlistentry>
@ -203,12 +205,12 @@
<term>detached</term>
<listitem>
<para>
この状態のインスタンスは、かつて永続コンテキストに関連づけられたが、
そのコンテキストがクローズされたか、あるいは、
他のプロセスにそのインスタンスがシリアライズされたかです。
このインスタンスは、永続IDを持ち、たいていはデータベースに
対応する行を持っているでしょう。分離インスタンスに対しては、
永続IDとJavaのIDとの関連は、Hibernateが保証しません。
この状態のインスタンスは、かつて永続コンテキストに関連づけられたが、
そのコンテキストがクローズされたか、あるいは、
他のプロセスにそのインスタンスがシリアライズされたかです。
このインスタンスは、永続IDを持ち、たいていはデータベースに
対応する行を持っているでしょう。分離インスタンスに対しては、
永続IDとJavaのIDとの関連は、Hibernateが保証しません。
</para>
</listitem>
</varlistentry>
@ -216,157 +218,157 @@
</sect1>
<sect1 id="architecture-jmx" revision="1">
<title>JMXとの統合</title>
<title>JMXとの統合</title>
<para>
JMXはJavaコンポーネント管理のJ2EE標準です。
JMX標準サービスを通して、Hibernateは管理されます。
ディストリビューションの中に <literal>org.hibernate.jmx.HibernateService</literal> という
MBean実装を用意しています。
JMXはJavaコンポーネント管理のJ2EE標準です。
JMX標準サービスを通して、Hibernateは管理されます。
ディストリビューションの中に <literal>org.hibernate.jmx.HibernateService</literal> という
MBean実装を用意しています。
</para>
<para>
JBoss アプリケーションサーバー上にHibernateをJMXサービスとしてデプロイする方法の例としては、
JBoss ユーザガイドを参照してください。 JBoss アプリケーションサーバーにおいて、
JMXを使ってデプロイすると、次のメリットが得られます。
JBoss アプリケーションサーバー上にHibernateをJMXサービスとしてデプロイする方法の例としては、
JBoss ユーザガイドを参照してください。 JBoss アプリケーションサーバーにおいて、
JMXを使ってデプロイすると、次のメリットが得られます。
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>セッション管理:</emphasis> Hibernateの <literal>Session</literal> のライフサイクルは、
自動的にJTAトランザクションのスコープに結びつけられます。これは、もはや手動で
<literal>Session</literal> をオープンしたり、クローズしたりする必要がないことを意味します。
これは、JBoss EJB インターセプタの仕事になります。
また、コードのどこでトランザクション境界を設定するかについて、
もはや悩む必要がありません(もちろん移植可能な永続層を書かかなくていいのならば、
オプションのHibernateの <literal>Transaction</literal> を使用してください。)
<literal>Session</literal> にアクセスするためには、 <literal>HibernateContext</literal>
コールしてください。
<emphasis>セッション管理:</emphasis> Hibernateの <literal>Session</literal> のライフサイクルは、
自動的にJTAトランザクションのスコープに結びつけられます。これは、もはや手動で
<literal>Session</literal> をオープンしたり、クローズしたりする必要がないことを意味します。
これは、JBoss EJB インターセプタの仕事になります。
また、コードのどこでトランザクション境界を設定するかについて、
もはや悩む必要がありません(もちろん移植可能な永続層を書かかなくていいのならば、
オプションのHibernateの <literal>Transaction</literal> を使用してください。)
<literal>Session</literal> にアクセスするためには、 <literal>HibernateContext</literal>
コールしてください。
</para>
</listitem>
<listitem>
<para>
<emphasis>HAR デプロイ:</emphasis> 通常、(EAR または SAR ファイルにあるJBoss サービス
デプロイメントディスクリプタを使って、Hibernate JMX サービスをデプロイします。
それは、Hibernateの <literal>SessionFactory</literal> の全ての一般的な設定オプションを
サポートします。しかし依然としてデプロイメントディスクリプタのなかにすべてのマッピングファイルの
名前を挙げる必要があります。
もし、オプションのHARデプロイメントを使うことを決めたなら、
JBossは自動的にHARファイルのなかの全てのマッピングファイルを検出します。
<emphasis>HAR デプロイ:</emphasis> 通常、(EAR または SAR ファイルにあるJBoss サービス
デプロイメントディスクリプタを使って、Hibernate JMX サービスをデプロイします。
それは、Hibernateの <literal>SessionFactory</literal> の全ての一般的な設定オプションを
サポートします。しかし依然としてデプロイメントディスクリプタのなかにすべてのマッピングファイルの
名前を挙げる必要があります。
もし、オプションのHARデプロイメントを使うことを決めたなら、
JBossは自動的にHARファイルのなかの全てのマッピングファイルを検出します。
</para>
</listitem>
</itemizedlist>
<para>
これらのオプションについての詳細な情報は、JBossアプリケーションサーバユーザガイドを
参考にしてください。
これらのオプションについての詳細な情報は、JBossアプリケーションサーバユーザガイドを
参考にしてください。
</para>
<para>
JMXサービスとして利用可能な他の機能に、Hibernate実行時統計情報があります。
<xref linkend="configuration-optional-statistics"/> を見てください。
JMXサービスとして利用可能な他の機能に、Hibernate実行時統計情報があります。
<xref linkend="configuration-optional-statistics"/> を見てください。
</para>
</sect1>
<sect1 id="architecture-jca" revision="1">
<title>JCA サポート</title>
<title>JCA サポート</title>
<para>
Hibernate は JCA コネクタとしても設定できます。詳細については、Webサイトを見てください。
Hibernate JCA サポートは、今のところ実験段階として考えられていることに注意してください。
Hibernate は JCA コネクタとしても設定できます。詳細については、Webサイトを見てください。
Hibernate JCA サポートは、今のところ実験段階として考えられていることに注意してください。
</para>
</sect1>
<sect1 id="architecture-current-session" revision="2">
<title>コンテキスト上のセッション</title>
<title>コンテキスト上のセッション</title>
<para>
Hibernate を使ったアプリケーションは、ほとんど、なんらかの形で"コンテキスト上の"セッションが必要になります。
「コンテキスト上のセッション」は、特定のコンテキストのスコープのなかで有効なセッションのことです。
しかし、通常アプリケーションごとにコンテキストを構成するものの定義は異なります。
しかも、異なる複数のコンテキストは、現時点に対して異なるスコープを定義します。
バージョン3.0より前の Hibernate では、自作の <literal>ThreadLocal</literal> ベースの「コンテキスト上のセッション」を
利用するか、 <literal>HibernateUtil</literal> のようなヘルパークラスを利用するか、
proxy/interception ベースの「コンテキスト上のセッション」を提供する
Spring や Pico のような)サードパーティのフレームワークを利用するかのいずれかでした。
Hibernate を使ったアプリケーションは、ほとんど、なんらかの形で"コンテキスト上の"セッションが必要になります。
「コンテキスト上のセッション」は、特定のコンテキストのスコープのなかで有効なセッションのことです。
しかし、通常アプリケーションごとにコンテキストを構成するものの定義は異なります。
しかも、異なる複数のコンテキストは、現時点に対して異なるスコープを定義します。
バージョン3.0より前の Hibernate では、自作の <literal>ThreadLocal</literal> ベースの「コンテキスト上のセッション」を
利用するか、 <literal>HibernateUtil</literal> のようなヘルパークラスを利用するか、
proxy/interception ベースの「コンテキスト上のセッション」を提供する
Spring や Pico のような)サードパーティのフレームワークを利用するかのいずれかでした。
</para>
<para>
バージョン 3.0.1 から、Hibernate には <literal>SessionFactory.getCurrentSession()</literal>
加わりました。 これは、 <literal>JTA</literal> トランザクションの使用を前提にしています。
<literal>JTA</literal> トランザクションは、現在のセッションのスコープとコンテキストの両方を定義します。
Hibernate チームは、次のことを主張します。
巨大なスタンドアロンの <literal>JTA TransactionManager</literal> 実装が成熟したら、
<literal>J2EE</literal> コンテナ上にデプロイされるかどうかにかかわらず、
ほとんどの(すべてとは言わないが)アプリケーションが、
<literal>JTA</literal> トランザクション管理を使用すべきであると。
この考えに基づくと、 <literal>JTA</literal> ベースの「コンテキスト上のセッション」を
使うしかないでしょう。
バージョン 3.0.1 から、Hibernate には <literal>SessionFactory.getCurrentSession()</literal>
加わりました。 これは、 <literal>JTA</literal> トランザクションの使用を前提にしています。
<literal>JTA</literal> トランザクションは、現在のセッションのスコープとコンテキストの両方を定義します。
Hibernate チームは、次のことを主張します。
巨大なスタンドアロンの <literal>JTA TransactionManager</literal> 実装が成熟したら、
<literal>J2EE</literal> コンテナ上にデプロイされるかどうかにかかわらず、
ほとんどの(すべてとは言わないが)アプリケーションが、
<literal>JTA</literal> トランザクション管理を使用すべきであると。
この考えに基づくと、 <literal>JTA</literal> ベースの「コンテキスト上のセッション」を
使うしかないでしょう。
</para>
<para>
しかし、バージョン 3.1 からは、 <literal>SessionFactory.getCurrentSession()</literal> の後の処理が、
プラガブルになりました。
これを受けて、現在のセッションを定義するスコープとコンテキストのプラガビリティを可能にするために、
新しい拡張インタフェース ( <literal>org.hibernate.context.CurrentSessionContext</literal> ) と
新しい構成パラメータ ( <literal>hibernate.current_session_context_class</literal> ) が追加されました。
しかし、バージョン 3.1 からは、 <literal>SessionFactory.getCurrentSession()</literal> の後の処理が、
プラガブルになりました。
これを受けて、現在のセッションを定義するスコープとコンテキストのプラガビリティを可能にするために、
新しい拡張インタフェース ( <literal>org.hibernate.context.CurrentSessionContext</literal> ) と
新しい構成パラメータ ( <literal>hibernate.current_session_context_class</literal> ) が追加されました。
</para>
<para>
<literal>org.hibernate.context.CurrentSessionContext</literal> インタフェースの規約についての
詳細な内容は Javadoc を参照してください。
それには、 <literal>currentSession()</literal> という1つのメソッドが定義されており、
その実装は、現在の「コンテキスト上のセッション」を追跡することに責任を持ちます。
そのまま使えるように、Hibernateはこのインタフェースの実装を2つ提供しています。
<literal>org.hibernate.context.CurrentSessionContext</literal> インタフェースの規約についての
詳細な内容は Javadoc を参照してください。
それには、 <literal>currentSession()</literal> という1つのメソッドが定義されており、
その実装は、現在の「コンテキスト上のセッション」を追跡することに責任を持ちます。
そのまま使えるように、Hibernateはこのインタフェースの実装を2つ提供しています。
</para>
<itemizedlist>
<listitem>
<para>
<literal>org.hibernate.context.JTASessionContext</literal> -
<literal>JTA</literal> トランザクションによって、現在のセッションが追跡され、
スコープを決められます。この処理は、古いJTAだけのアプローチとまったく同じです。
詳細はJavadocを参照してください。
<literal>JTA</literal> トランザクションによって、現在のセッションが追跡され、
スコープを決められます。この処理は、古いJTAだけのアプローチとまったく同じです。
詳細はJavadocを参照してください。
</para>
</listitem>
<listitem>
<para>
<literal>org.hibernate.context.ThreadLocalSessionContext</literal> -
スレッドの実行によって、現在のセッションが追跡されます。
詳細はJavadocを参照してください。
スレッドの実行によって、現在のセッションが追跡されます。
詳細はJavadocを参照してください。
</para>
</listitem>
<listitem>
<para>
<literal>org.hibernate.context.ManagedSessionContext</literal> -
スレッドの実行によって、現在のセッションが追跡されます。
しかし、このクラスのstaticメソッドで <literal>Session</literal> インスタンスを
バインド/アンバインドする責任はあなたにあります。
これは決して <literal>Session</literal> をオープン、フラッシュ、クローズしません。
スレッドの実行によって、現在のセッションが追跡されます。
しかし、このクラスのstaticメソッドで <literal>Session</literal> インスタンスを
バインド/アンバインドする責任はあなたにあります。
これは決して <literal>Session</literal> をオープン、フラッシュ、クローズしません。
</para>
</listitem>
</itemizedlist>
<para>
始めの2つの実装は、"1セッション - 1データベーストランザクション" プログラミングモデルを提供します。
これは <emphasis>リクエストごとのセッションsession-per-request</emphasis> としても知られており、使われています。
Hibernate セッションの開始と終了は、データベーストランザクションの期間で決まります。
JTAを使わない普通のJSEで、プログラム上のトランザクション境界設定を行うなら、
コードから基礎のトランザクションシステムを隠蔽するために、
Hibernate <literal>Transaction</literal> APIを使うとよいでしょう。
JTAを使うなら、トランザクションの境界設定には、JTAインターフェイスを使ってください。
CMTをサポートするEJBコンテナで実行するつもりなら、トランザクション境界は宣言的に定義できるため、
コード上でトランザクションやセッションの境界を設定する必要はありません。
さらに詳細な情報やコードの例は、 <xref linkend="transactions"/> を参照してください。
始めの2つの実装は、"1セッション - 1データベーストランザクション" プログラミングモデルを提供します。
これは <emphasis>リクエストごとのセッションsession-per-request</emphasis> としても知られており、使われています。
Hibernate セッションの開始と終了は、データベーストランザクションの期間で決まります。
JTAを使わない普通のJSEで、プログラム上のトランザクション境界設定を行うなら、
コードから基礎のトランザクションシステムを隠蔽するために、
Hibernate <literal>Transaction</literal> APIを使うとよいでしょう。
JTAを使うなら、トランザクションの境界設定には、JTAインターフェイスを使ってください。
CMTをサポートするEJBコンテナで実行するつもりなら、トランザクション境界は宣言的に定義できるため、
コード上でトランザクションやセッションの境界を設定する必要はありません。
さらに詳細な情報やコードの例は、 <xref linkend="transactions"/> を参照してください。
</para>
<para>
<literal>hibernate.current_session_context_class</literal> 設定パラメータは、
<literal>org.hibernate.context.CurrentSessionContext</literal> のどの実装を使うかを指定します。
下位互換性のため、このパラメータが設定されず
<literal>org.hibernate.transaction.TransactionManagerLookup</literal> が設定されていた場合、
Hibernateは <literal>org.hibernate.context.JTASessionContext</literal> を使うことに注意してください。
通常このパラメータの値には、3つの実装の中から使用する実装クラスの名前を直接指定します。
しかし、"jta", "thread", "managed"というそれぞれの省略名も用意されています。
<literal>hibernate.current_session_context_class</literal> 設定パラメータは、
<literal>org.hibernate.context.CurrentSessionContext</literal> のどの実装を使うかを指定します。
下位互換性のため、このパラメータが設定されず
<literal>org.hibernate.transaction.TransactionManagerLookup</literal> が設定されていた場合、
Hibernateは <literal>org.hibernate.context.JTASessionContext</literal> を使うことに注意してください。
通常このパラメータの値には、3つの実装の中から使用する実装クラスの名前を直接指定します。
しかし、"jta", "thread", "managed"というそれぞれの省略名も用意されています。
</para>
</sect1>

View File

@ -1,39 +1,41 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="associations">
<title>関連マッピング</title>
<title>関連マッピング</title>
<sect1 id="assoc-intro" revision="1">
<title>イントロダクション</title>
<title>イントロダクション</title>
<para>
関連マッピングはしばしば理解が最も難しいものになります。
この章では、基本的な一つ一つのケースについて述べます。
単方向のマッピングから始め、それから双方向のケースについて考えていきます。
例として、<literal>Person</literal><literal>Address</literal> を用います。
関連マッピングはしばしば理解が最も難しいものになります。
この章では、基本的な一つ一つのケースについて述べます。
単方向のマッピングから始め、それから双方向のケースについて考えていきます。
例として、<literal>Person</literal><literal>Address</literal> を用います。
</para>
<para>
関連は、結合テーブルを入れるかかどうかと、
多重度によって分類することにします。
関連は、結合テーブルを入れるかかどうかと、
多重度によって分類することにします。
</para>
<para>
すべての例でnot nullの外部キーを使用します。
これはHibernateの要件ではありません。
not null制約を外したとしても、マッピングは問題なく動作します。
すべての例でnot nullの外部キーを使用します。
これはHibernateの要件ではありません。
not null制約を外したとしても、マッピングは問題なく動作します。
</para>
</sect1>
<sect1 id="assoc-unidirectional" revision="1">
<title>単方向関連</title>
<title>単方向関連</title>
<sect2 id="assoc-unidirectional-m21">
<title>多対一</title>
<title>多対一</title>
<para>
<emphasis>単方向多対一関連</emphasis> は単方向関連の中で最も一般的なものです。
<emphasis>単方向多対一関連</emphasis> は単方向関連の中で最も一般的なものです。
</para>
<programlisting><![CDATA[<class name="Person">
@ -58,11 +60,11 @@ create table Address ( addressId bigint not null primary key )
</sect2>
<sect2 id="assoc-unidirectional-121">
<title>一対一</title>
<title>一対一</title>
<para>
<emphasis>外部キーの単方向一対一関連</emphasis> はほとんど同じものです。
唯一違うのは、カラムのユニークな制約です。
<emphasis>外部キーの単方向一対一関連</emphasis> はほとんど同じものです。
唯一違うのは、カラムのユニークな制約です。
</para>
<programlisting><![CDATA[<class name="Person">
@ -86,8 +88,8 @@ create table Address ( addressId bigint not null primary key )
]]></programlisting>
<para>
<emphasis>主キーの単方向一対一関連</emphasis> は通常、特別なIDジェネレータを使います。
(この例では関連の方向が逆になっていることに注意してください)
<emphasis>主キーの単方向一対一関連</emphasis> は通常、特別なIDジェネレータを使います。
(この例では関連の方向が逆になっていることに注意してください)
</para>
<programlisting><![CDATA[<class name="Person">
@ -112,11 +114,11 @@ create table Address ( personId bigint not null primary key )
</sect2>
<sect2 id="assoc-unidirectional-12m">
<title>一対多</title>
<title>一対多</title>
<para>
<emphasis>外部キーの単方向一対多関連</emphasis> はとても特殊なケースで、
あまり推奨されていません。
<emphasis>外部キーの単方向一対多関連</emphasis> はとても特殊なケースで、
あまり推奨されていません。
</para>
<programlisting><![CDATA[<class name="Person">
@ -141,7 +143,7 @@ create table Address ( addressId bigint not null primary key, personId bigint no
]]></programlisting>
<para>
このような関連のために結合テーブルを使うことをお薦めします。
このような関連のために結合テーブルを使うことをお薦めします。
</para>
</sect2>
@ -149,16 +151,16 @@ create table Address ( addressId bigint not null primary key, personId bigint no
</sect1>
<sect1 id="assoc-unidirectional-join" revision="1">
<title>結合テーブルを使った単方向関連</title>
<title>結合テーブルを使った単方向関連</title>
<sect2 id="assoc-unidirectional-join-12m">
<title>一対多</title>
<title>一対多</title>
<para>
<emphasis>結合テーブルを使った単方向一対多関連</emphasis>
はより好ましいです。
<literal>unique="true"</literal> の指定により、多重度が多対多から一対多
に変わったことに注意して下さい。
<emphasis>結合テーブルを使った単方向一対多関連</emphasis>
はより好ましいです。
<literal>unique="true"</literal> の指定により、多重度が多対多から一対多
に変わったことに注意して下さい。
</para>
<programlisting><![CDATA[<class name="Person">
@ -187,11 +189,11 @@ create table Address ( addressId bigint not null primary key )
</sect2>
<sect2 id="assoc-unidirectional-join-m21">
<title>多対一</title>
<title>多対一</title>
<para>
<emphasis>結合テーブルの単方向多対一関連</emphasis>
関連が任意であるときに非常に一般的なものです。
<emphasis>結合テーブルの単方向多対一関連</emphasis>
関連が任意であるときに非常に一般的なものです。
</para>
<programlisting><![CDATA[<class name="Person">
@ -221,11 +223,11 @@ create table Address ( addressId bigint not null primary key )
</sect2>
<sect2 id="assoc-unidirectional-join-121">
<title>一対一</title>
<title>一対一</title>
<para>
<emphasis>結合テーブルの単方向一対一関連</emphasis> は、本当に特殊ですが
不可能ではありません。
<emphasis>結合テーブルの単方向一対一関連</emphasis> は、本当に特殊ですが
不可能ではありません。
</para>
<programlisting><![CDATA[<class name="Person">
@ -257,10 +259,10 @@ create table Address ( addressId bigint not null primary key )
</sect2>
<sect2 id="assoc-unidirectional-join-m2m">
<title>多対多</title>
<title>多対多</title>
<para>
最後に、<emphasis>単方向多対多関連</emphasis> を示します。
最後に、<emphasis>単方向多対多関連</emphasis> を示します。
</para>
<programlisting><![CDATA[<class name="Person">
@ -290,14 +292,14 @@ create table Address ( addressId bigint not null primary key )
</sect1>
<sect1 id="assoc-bidirectional" revision="1">
<title>双方向関連</title>
<title>双方向関連</title>
<sect2 id="assoc-bidirectional-m21" revision="2">
<title>一対多/多対一</title>
<title>一対多/多対一</title>
<para>
<emphasis>双方向多対一関連</emphasis> は最も一般的な関連です。
(標準的な親子関係です)
<emphasis>双方向多対一関連</emphasis> は最も一般的な関連です。
(標準的な親子関係です)
</para>
<programlisting><![CDATA[<class name="Person">
@ -325,12 +327,12 @@ create table Address ( addressId bigint not null primary key )
]]></programlisting>
<para>
<literal>List</literal> (または他のインデックス付きのコレクション)を使うなら、
外部キーの <literal>key</literal> カラムを <literal>not null</literal> に設定し、
コレクション側が各要素のインデックスをメンテナンスするように、
関連を扱う必要があります
<literal>update="false"</literal> かつ <literal>insert="false"</literal>
と設定して、反対側を仮想的にinverseにします
<literal>List</literal> (または他のインデックス付きのコレクション)を使うなら、
外部キーの <literal>key</literal> カラムを <literal>not null</literal> に設定し、
コレクション側が各要素のインデックスをメンテナンスするように、
関連を扱う必要があります
<literal>update="false"</literal> かつ <literal>insert="false"</literal>
と設定して、反対側を仮想的にinverseにします
</para>
<programlisting><![CDATA[<class name="Person">
@ -354,21 +356,21 @@ create table Address ( addressId bigint not null primary key )
</class>]]></programlisting>
<para>
もし外部キーカラムが <literal>NOT NULL</literal> であるならば、
コレクションマッピングの <literal>&lt;key&gt;</literal> 要素を
<literal>not-null="true"</literal> にすることは重要です。
入れ子になった <literal>&lt;column&gt;</literal> 要素だけではなく、
<literal>&lt;key&gt;</literal> 要素も <literal>not-null="true"</literal>
と定義しないようにしてください。
もし外部キーカラムが <literal>NOT NULL</literal> であるならば、
コレクションマッピングの <literal>&lt;key&gt;</literal> 要素を
<literal>not-null="true"</literal> にすることは重要です。
入れ子になった <literal>&lt;column&gt;</literal> 要素だけではなく、
<literal>&lt;key&gt;</literal> 要素も <literal>not-null="true"</literal>
と定義しないようにしてください。
</para>
</sect2>
<sect2 id="assoc-bidirectional-121">
<title>一対一</title>
<title>一対一</title>
<para>
<emphasis>外部キーの双方向一対一関連</emphasis> は非常に一般的です。
<emphasis>外部キーの双方向一対一関連</emphasis> は非常に一般的です。
</para>
<programlisting><![CDATA[<class name="Person">
@ -394,7 +396,7 @@ create table Address ( addressId bigint not null primary key )
]]></programlisting>
<para>
<emphasis>主キーの双方向一対一関連</emphasis> は特殊なIDジェネレータを使います。
<emphasis>主キーの双方向一対一関連</emphasis> は特殊なIDジェネレータを使います。
</para>
<programlisting><![CDATA[<class name="Person">
@ -423,15 +425,15 @@ create table Address ( personId bigint not null primary key )
</sect1>
<sect1 id="assoc-bidirectional-join" revision="1">
<title>結合テーブルを使った双方向関連</title>
<title>結合テーブルを使った双方向関連</title>
<sect2 id="assoc-bidirectional-join-12m">
<title>一対多/多対一</title>
<title>一対多/多対一</title>
<para>
<emphasis>結合テーブルの双方向一対多関連</emphasis> です。
<literal>inverse="true"</literal> が関連端、コレクション、結合のいずれかに
設定できることに注意してください。
<emphasis>結合テーブルの双方向一対多関連</emphasis> です。
<literal>inverse="true"</literal> が関連端、コレクション、結合のいずれかに
設定できることに注意してください。
</para>
<programlisting><![CDATA[<class name="Person">
@ -469,11 +471,11 @@ create table Address ( addressId bigint not null primary key )
</sect2>
<sect2 id="assoc-bidirectional-join-121">
<title>一対一</title>
<title>一対一</title>
<para>
<emphasis>結合テーブルの双方向一対一関連</emphasis>
は非常に特殊ですが、可能です。
<emphasis>結合テーブルの双方向一対一関連</emphasis>
は非常に特殊ですが、可能です。
</para>
<programlisting><![CDATA[<class name="Person">
@ -515,10 +517,10 @@ create table Address ( addressId bigint not null primary key )
</sect2>
<sect2 id="assoc-bidirectional-join-m2m" revision="1">
<title>多対多</title>
<title>多対多</title>
<para>
最後に、<emphasis>双方向多対多関連</emphasis> を示します。
最後に、<emphasis>双方向多対多関連</emphasis> を示します。
</para>
<programlisting><![CDATA[<class name="Person">
@ -554,15 +556,15 @@ create table Address ( addressId bigint not null primary key )
</sect1>
<sect1 id="assoc-complex">
<title>より複雑な関連マッピング</title>
<title>より複雑な関連マッピング</title>
<para>
より複雑な関連結合は <emphasis>極めて</emphasis> 稀です。
マッピングドキュメントにSQL文を埋め込むことで、
さらに複雑な状況を扱うことができます。
例えば、<literal>accountNumber</literal>, <literal>effectiveEndDate</literal>,
<literal>effectiveStartDate</literal> カラムを持つaccount口座情報の履歴を扱うテーブルは、
以下のようにマッピングします。
より複雑な関連結合は <emphasis>極めて</emphasis> 稀です。
マッピングドキュメントにSQL文を埋め込むことで、
さらに複雑な状況を扱うことができます。
例えば、<literal>accountNumber</literal>, <literal>effectiveEndDate</literal>,
<literal>effectiveStartDate</literal> カラムを持つaccount口座情報の履歴を扱うテーブルは、
以下のようにマッピングします。
</para>
<programlisting><![CDATA[<properties name="currentAccountKey">
@ -575,9 +577,9 @@ create table Address ( addressId bigint not null primary key )
<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
<para>
そして、関連を <emphasis>現時点の</emphasis> インスタンス
<literal>effectiveEndDate</literal> がnullであるものにマッピングします。
以下のようになります:
そして、関連を <emphasis>現時点の</emphasis> インスタンス
<literal>effectiveEndDate</literal> がnullであるものにマッピングします。
以下のようになります:
</para>
<programlisting><![CDATA[<many-to-one name="currentAccountInfo"
@ -588,11 +590,11 @@ create table Address ( addressId bigint not null primary key )
</many-to-one>]]></programlisting>
<para>
さらに複雑な例では、<literal>Employee従業員</literal><literal>Organization組織</literal>
間の関連が <literal>Employment雇用</literal> テーブルで保持される場合を想像してください。
このテーブルには雇用データの履歴がすべて含まれます。
すると従業員の <emphasis>最も最近の</emphasis> 雇用者を表す関連
(最も最近の <literal>startDate</literal> を持つもの)は、このようにマッピングできます:
さらに複雑な例では、<literal>Employee従業員</literal><literal>Organization組織</literal>
間の関連が <literal>Employment雇用</literal> テーブルで保持される場合を想像してください。
このテーブルには雇用データの履歴がすべて含まれます。
すると従業員の <emphasis>最も最近の</emphasis> 雇用者を表す関連
(最も最近の <literal>startDate</literal> を持つもの)は、このようにマッピングできます:
</para>
<programlisting><![CDATA[<join>
@ -609,8 +611,8 @@ create table Address ( addressId bigint not null primary key )
</join>]]></programlisting>
<para>
この機能は非常に強力です。
しかしこのような場合、普通はHQLやcriteriaクエリを使う方がより実践的です。
この機能は非常に強力です。
しかしこのような場合、普通はHQLやcriteriaクエリを使う方がより実践的です。
</para>
</sect1>

View File

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="batch">
<title>バッチ処理</title>
<title>バッチ処理</title>
<para>
Hibernateを使ってデータベースに100,000行を挿入する愚直な方法は、このようなものです
Hibernateを使ってデータベースに100,000行を挿入する愚直な方法は、このようなものです
</para>
<programlisting><![CDATA[Session session = sessionFactory.openSession();
@ -16,42 +18,42 @@ tx.commit();
session.close();]]></programlisting>
<para>
これは50,000番目の行のあたりで <literal>OutOfMemoryException</literal> で失敗するでしょう。
Hibernateがセッションレベルキャッシュで、
新しく挿入されたすべての <literal>Customer</literal>
インスタンスをキャッシュするからです。
これは50,000番目の行のあたりで <literal>OutOfMemoryException</literal> で失敗するでしょう。
Hibernateがセッションレベルキャッシュで、
新しく挿入されたすべての <literal>Customer</literal>
インスタンスをキャッシュするからです。
</para>
<para>
この章では、この問題を回避する方法を紹介します。
しかしバッチ処理をするなら、JDBCバッチが使用可能であることが非常に重要です。
そうでなければ手頃なパフォーマンスが得られません。
JDBCバッチサイズを手頃な数値例えば、10から50に設定してください
この章では、この問題を回避する方法を紹介します。
しかしバッチ処理をするなら、JDBCバッチが使用可能であることが非常に重要です。
そうでなければ手頃なパフォーマンスが得られません。
JDBCバッチサイズを手頃な数値例えば、10から50に設定してください
</para>
<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
<para>
また二次キャッシュが全く効かないプロセスで、
このような作業をしたいと思うかもしれません:
また二次キャッシュが全く効かないプロセスで、
このような作業をしたいと思うかもしれません:
</para>
<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
<para>
しかし、これは絶対に必要というわけではありません。
なぜなら明示的に <literal>CacheMode</literal> を設定して、
二次キャッシュとの相互作用を無効にすることができるからです。
しかし、これは絶対に必要というわけではありません。
なぜなら明示的に <literal>CacheMode</literal> を設定して、
二次キャッシュとの相互作用を無効にすることができるからです。
</para>
<sect1 id="batch-inserts">
<title>バッチ挿入</title>
<title>バッチ挿入</title>
<para>
新しいオブジェクトを永続化するとき、一次キャッシュのサイズを制限するため、
セッションを <literal>flush()</literal> して <literal>clear()</literal>
しなければなりません。
新しいオブジェクトを永続化するとき、一次キャッシュのサイズを制限するため、
セッションを <literal>flush()</literal> して <literal>clear()</literal>
しなければなりません。
</para>
<programlisting><![CDATA[Session session = sessionFactory.openSession();
@ -73,13 +75,13 @@ session.close();]]></programlisting>
</sect1>
<sect1 id="batch-update" >
<title>バッチ更新</title>
<title>バッチ更新</title>
<para>
データを復元したり更新したりするには同じアイディアを適用します。
それに加えて、データの行を多く返すクエリに対して有効な
サーバーサイドのカーソルの利点を生かしたければ
<literal>scroll()</literal> を使う必要があります。
データを復元したり更新したりするには同じアイディアを適用します。
それに加えて、データの行を多く返すクエリに対して有効な
サーバーサイドのカーソルの利点を生かしたければ
<literal>scroll()</literal> を使う必要があります。
</para>
<programlisting><![CDATA[Session session = sessionFactory.openSession();
@ -106,26 +108,26 @@ session.close();]]></programlisting>
<sect1 id="batch-statelesssession">
<title>
StatelessSessionインターフェイス
StatelessSessionインターフェイス
</title>
<para>
また別の方法として、Hibernateはコマンド指向のAPIを用意しています。
これは分離オブジェクトの形で、
データベースとのデータストリームのやり取りに使うことができます。
<literal>StatelessSession</literal> は関連する永続コンテキストを持たず、
高レベルのライフサイクルセマンティクスの多くを提供しません。
特にステートレスセッションは、一時キャッシュを実装せず、
またどのような二次キャッシュやクエリキャッシュとも相互作用しません。
トランザクショナルなwrite-behindや自動ダーティチェックも実装しません。
ステートレスセッションを使って行われる操作が、
関連するインスタンスへカスケードされることは決してありません。
コレクションは、ステートレスセッションからは無視されます。
ステートレスセッションを通して行われる操作は、
Hibernateのイベントモデルやインターセプタの影響を受けません。
一時キャッシュを持たないため、
ステートレスセッションは別名を持つデータに上手く対処できません。
ステートレスセッションは低レベルの抽象化であり、JDBCに非常によく似ています。
また別の方法として、Hibernateはコマンド指向のAPIを用意しています。
これは分離オブジェクトの形で、
データベースとのデータストリームのやり取りに使うことができます。
<literal>StatelessSession</literal> は関連する永続コンテキストを持たず、
高レベルのライフサイクルセマンティクスの多くを提供しません。
特にステートレスセッションは、一時キャッシュを実装せず、
またどのような二次キャッシュやクエリキャッシュとも相互作用しません。
トランザクショナルなwrite-behindや自動ダーティチェックも実装しません。
ステートレスセッションを使って行われる操作が、
関連するインスタンスへカスケードされることは決してありません。
コレクションは、ステートレスセッションからは無視されます。
ステートレスセッションを通して行われる操作は、
Hibernateのイベントモデルやインターセプタの影響を受けません。
一時キャッシュを持たないため、
ステートレスセッションは別名を持つデータに上手く対処できません。
ステートレスセッションは低レベルの抽象化であり、JDBCに非常によく似ています。
</para>
@ -144,20 +146,20 @@ tx.commit();
session.close();]]></programlisting>
<para>
このコード例では、クエリが返す <literal>Customer</literal>
インスタンスは即座に(セッションから)分離されることに注意してください。
これは、どのような永続コンテキストとも決して関連しません。
このコード例では、クエリが返す <literal>Customer</literal>
インスタンスは即座に(セッションから)分離されることに注意してください。
これは、どのような永続コンテキストとも決して関連しません。
</para>
<para>
<literal>StatelessSession</literal> インターフェイスで定義されている
<literal>insert(), update(), delete()</literal> は、
低レベルの直接的なデータベース操作と考えられます。
結果として、SQLの <literal>INSERT, UPDATE, DELETE</literal> がそれぞれ即座に実行されます。
このように、これらは <literal>Session</literal> インターフェイスで定義されている
<literal>StatelessSession</literal> インターフェイスで定義されている
<literal>insert(), update(), delete()</literal> は、
低レベルの直接的なデータベース操作と考えられます。
結果として、SQLの <literal>INSERT, UPDATE, DELETE</literal> がそれぞれ即座に実行されます。
このように、これらは <literal>Session</literal> インターフェイスで定義されている
<literal>save(), saveOrUpdate(), delete()</literal>
とは非常に異なる意味を持ちます。
とは非常に異なる意味を持ちます。
</para>
@ -165,68 +167,68 @@ session.close();]]></programlisting>
<sect1 id="batch-direct" revision="3">
<title>
DMLスタイルの操作
DMLスタイルの操作
</title>
<para>
すでに議論したように、自動的かつ透過的なオブジェクト/リレーショナルマッピングは、
オブジェクトの状態の管理であると考えられます。
これはメモリ内のオブジェクトの状態を利用できるということです。
そのためSQLの <literal>データ操作言語</literal> (DML) 文:
すでに議論したように、自動的かつ透過的なオブジェクト/リレーショナルマッピングは、
オブジェクトの状態の管理であると考えられます。
これはメモリ内のオブジェクトの状態を利用できるということです。
そのためSQLの <literal>データ操作言語</literal> (DML) 文:
<literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>
を使って)データベース内のデータを直接操作しても、
メモリ内の状態には影響を与えません。
しかしHibernateは、バルクSQLスタイルのDML文実行に対応するメソッドを用意しています。
これはHibernateクエリ言語<xref linkend="queryhql">HQL</xref>
を通して実行されます。
を使って)データベース内のデータを直接操作しても、
メモリ内の状態には影響を与えません。
しかしHibernateは、バルクSQLスタイルのDML文実行に対応するメソッドを用意しています。
これはHibernateクエリ言語<xref linkend="queryhql">HQL</xref>
を通して実行されます。
</para>
<para>
<literal>UPDATE</literal><literal>DELETE</literal> 文の疑似構文は:
<literal>( UPDATE | DELETE ) FROM? エンティティ名 (WHERE 条件節)?</literal> です。
注意すべき点がいくつかあります:
<literal>UPDATE</literal><literal>DELETE</literal> 文の疑似構文は:
<literal>( UPDATE | DELETE ) FROM? エンティティ名 (WHERE 条件節)?</literal> です。
注意すべき点がいくつかあります:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
from節において、FROMキーワードはオプションです。
from節において、FROMキーワードはオプションです。
</para>
</listitem>
<listitem>
<para>
from節では単一のエンティティ名だけが可能で、
任意で別名を付けることができます。
エンティティ名に別名が与えられると、どのようなプロパティ参照も、
その別名を使って修飾しなければなりません。
もしエンティティ名に別名が与えられなければ、
どのようなプロパティ参照も修飾してはなりません。
from節では単一のエンティティ名だけが可能で、
任意で別名を付けることができます。
エンティティ名に別名が与えられると、どのようなプロパティ参照も、
その別名を使って修飾しなければなりません。
もしエンティティ名に別名が与えられなければ、
どのようなプロパティ参照も修飾してはなりません。
</para>
</listitem>
<listitem>
<para>
(暗黙的であれ明示的であれ)<xref linkend="queryhql-joins-forms">結合</xref>
をバルクHQLクエリ内で指定することはできません。
サブクエリはwhere節で使うことができます
サブクエリそのものは、結合を含められます。
(暗黙的であれ明示的であれ)<xref linkend="queryhql-joins-forms">結合</xref>
をバルクHQLクエリ内で指定することはできません。
サブクエリはwhere節で使うことができます
サブクエリそのものは、結合を含められます。
</para>
</listitem>
<listitem>
<para>
where節はオプションです。
where節はオプションです。
</para>
</listitem>
</itemizedlist>
<para>
例として、HQLの <literal>UPDATE</literal> を実行するには、
<literal>Query.executeUpdate()</literal> メソッドを使ってください。
このメソッドはおなじみのJDBC <literal>PreparedStatement.executeUpdate()</literal>
から名付けられました):
例として、HQLの <literal>UPDATE</literal> を実行するには、
<literal>Query.executeUpdate()</literal> メソッドを使ってください。
このメソッドはおなじみのJDBC <literal>PreparedStatement.executeUpdate()</literal>
から名付けられました):
d
</para>
@ -243,16 +245,16 @@ tx.commit();
session.close();]]></programlisting>
<para>
HQLの <literal>UPDATE</literal> 文は、デフォルトでは、作用するエンティティの
<xref linkend="mapping-declaration-version">version</xref>
HQLの <literal>UPDATE</literal> 文は、デフォルトでは、作用するエンティティの
<xref linkend="mapping-declaration-version">version</xref>
<xref linkend="mapping-declaration-timestamp">timestamp</xref>
プロパティの値には影響しません。
これはEJB3の仕様にも受け継がれています。
しかし <literal>versioned update</literal> を使って、
<literal>version</literal><literal>timestamp</literal>
プロパティの値を強制的にリセットさせることができます。
これは <literal>UPDATE</literal> キーワードの後に <literal>VERSIONED</literal>
キーワードを追加することで行えます。
プロパティの値には影響しません。
これはEJB3の仕様にも受け継がれています。
しかし <literal>versioned update</literal> を使って、
<literal>version</literal><literal>timestamp</literal>
プロパティの値を強制的にリセットさせることができます。
これは <literal>UPDATE</literal> キーワードの後に <literal>VERSIONED</literal>
キーワードを追加することで行えます。
</para>
<programlisting><![CDATA[Session session = sessionFactory.openSession();
@ -266,13 +268,13 @@ tx.commit();
session.close();]]></programlisting>
<para>
カスタムバージョン型(<literal>org.hibernate.usertype.UserVersionType</literal>
<literal>update versioned</literal> 文と一緒に使えないことに注意してください。
カスタムバージョン型(<literal>org.hibernate.usertype.UserVersionType</literal>
<literal>update versioned</literal> 文と一緒に使えないことに注意してください。
</para>
<para>
HQLの <literal>DELETE</literal> を実行するには、
同じ <literal>Query.executeUpdate()</literal> メソッドを使ってください:
HQLの <literal>DELETE</literal> を実行するには、
同じ <literal>Query.executeUpdate()</literal> メソッドを使ってください:
</para>
@ -288,87 +290,87 @@ tx.commit();
session.close();]]></programlisting>
<para>
<literal>Query.executeUpdate()</literal> メソッドが返す <literal>int</literal>
の値は、この操作が影響を及ぼしたエンティティの数です。
これが影響するデータベース内の行数と、相互に関係するかどうかを考えてみてください。
HQLバルク操作は、結果として、実際のSQL文が複数実行されることになります。
例えばjoined-subclassです。
返される数は、その文によって影響された実際のエンティティの数を示します。
joined-subclassの例に戻ると、サブクラスの一つに対する削除は、
そのサブクラスがマッピングされたテーブルだけではなく、
「ルート」テーブルと継承階層をさらに下ったjoined-subclassのテーブルの削除になります。
<literal>Query.executeUpdate()</literal> メソッドが返す <literal>int</literal>
の値は、この操作が影響を及ぼしたエンティティの数です。
これが影響するデータベース内の行数と、相互に関係するかどうかを考えてみてください。
HQLバルク操作は、結果として、実際のSQL文が複数実行されることになります。
例えばjoined-subclassです。
返される数は、その文によって影響された実際のエンティティの数を示します。
joined-subclassの例に戻ると、サブクラスの一つに対する削除は、
そのサブクラスがマッピングされたテーブルだけではなく、
「ルート」テーブルと継承階層をさらに下ったjoined-subclassのテーブルの削除になります。
</para>
<para>
<literal>INSERT</literal> 文の疑似構文は:
<literal>INSERT INTO エンティティ名 プロパティリスト select文</literal> です。
注意すべき点がいくつかあります:
<literal>INSERT</literal> 文の疑似構文は:
<literal>INSERT INTO エンティティ名 プロパティリスト select文</literal> です。
注意すべき点がいくつかあります:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
INSERT INTO ... SELECT ... の形式だけがサポートされています。
INSERT INTO ... VALUES ... の形式はサポートされていません。
INSERT INTO ... SELECT ... の形式だけがサポートされています。
INSERT INTO ... VALUES ... の形式はサポートされていません。
</para>
<para>
プロパティリストは、SQLの <literal>INSERT</literal> 文における <literal>カラムの仕様</literal>
に類似しています。
継承のマッピングに含まれるエンティティに対して、
クラスレベルで直接定義されたプロパティだけが、プロパティリストに使えます。
スーパークラスのプロパティは認められず、サブクラスのプロパティは効果がありません。
言い換えると <literal>INSERT</literal> 文は、本質的にポリモーフィックではありません。
プロパティリストは、SQLの <literal>INSERT</literal> 文における <literal>カラムの仕様</literal>
に類似しています。
継承のマッピングに含まれるエンティティに対して、
クラスレベルで直接定義されたプロパティだけが、プロパティリストに使えます。
スーパークラスのプロパティは認められず、サブクラスのプロパティは効果がありません。
言い換えると <literal>INSERT</literal> 文は、本質的にポリモーフィックではありません。
</para>
</listitem>
<listitem>
<para>
select文の返り値の型がinsert文が期待する型とマッチしていれば、
そのselect文は妥当なHQL selectクエリとなりえます。
現在このチェックをデータベースへ任せるのではなく、クエリのコンパイル時にチェックします。
このことは、<emphasis>equal</emphasis>とは違い、
Hibernateの <literal>Type</literal> 間の <emphasis>equivalent</emphasis> に関する
問題を引き起こすことに注意してください。
これは <literal>org.hibernate.type.DataType</literal> として定義されたプロパティと、
select文の返り値の型がinsert文が期待する型とマッチしていれば、
そのselect文は妥当なHQL selectクエリとなりえます。
現在このチェックをデータベースへ任せるのではなく、クエリのコンパイル時にチェックします。
このことは、<emphasis>equal</emphasis>とは違い、
Hibernateの <literal>Type</literal> 間の <emphasis>equivalent</emphasis> に関する
問題を引き起こすことに注意してください。
これは <literal>org.hibernate.type.DataType</literal> として定義されたプロパティと、
<literal>org.hibernate.type.TimestampType</literal>
として定義されたプロパティの間のミスマッチの問題を引き起こします。
データベースがそれらを区別できなくても、変換することができても、この問題は発生します。
として定義されたプロパティの間のミスマッチの問題を引き起こします。
データベースがそれらを区別できなくても、変換することができても、この問題は発生します。
</para>
</listitem>
<listitem>
<para>
idプロパティに対して、insert文には二つの選択肢があります。
プロパティリストで明示的にidプロパティを指定するか
この場合、対応するselect式から値が取られます
プロパティリストから除外するか
(この場合、生成される値が使われます)のいずれかです。
後者の選択肢は、データベース内を操作するidジェネレータを使うときのみ、利用可能です。
この選択肢を採る場合、「インメモリ」型のジェネレータを使うと、構文解析時に例外が発生します。
この議論では、インデータベース型ジェネレータは <literal>org.hibernate.id.SequenceGenerator</literal>
(とそのサブクラス)と、<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>
の実装であると考えています。
ここで最も注意すべき例外は、<literal>org.hibernate.id.TableHiLoGenerator</literal> です。
値を取得する選択可能な方法がないため、このジェネレータを使うことはできません。
idプロパティに対して、insert文には二つの選択肢があります。
プロパティリストで明示的にidプロパティを指定するか
この場合、対応するselect式から値が取られます
プロパティリストから除外するか
(この場合、生成される値が使われます)のいずれかです。
後者の選択肢は、データベース内を操作するidジェネレータを使うときのみ、利用可能です。
この選択肢を採る場合、「インメモリ」型のジェネレータを使うと、構文解析時に例外が発生します。
この議論では、インデータベース型ジェネレータは <literal>org.hibernate.id.SequenceGenerator</literal>
(とそのサブクラス)と、<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>
の実装であると考えています。
ここで最も注意すべき例外は、<literal>org.hibernate.id.TableHiLoGenerator</literal> です。
値を取得する選択可能な方法がないため、このジェネレータを使うことはできません。
</para>
</listitem>
<listitem>
<para>
<literal>version</literal><literal>timestamp</literal> としてマッピングされるプロパティに対して、
insert文には二つの選択肢があります。
プロパティリストで明示的にプロパティを指定するか
この場合、対応するselect式から値が取られます
プロパティリストから除外するか
(この場合、<literal>org.hibernate.type.VersionType</literal> で定義された
<literal>シード値</literal> が使われます)のいずれかです。
<literal>version</literal><literal>timestamp</literal> としてマッピングされるプロパティに対して、
insert文には二つの選択肢があります。
プロパティリストで明示的にプロパティを指定するか
この場合、対応するselect式から値が取られます
プロパティリストから除外するか
(この場合、<literal>org.hibernate.type.VersionType</literal> で定義された
<literal>シード値</literal> が使われます)のいずれかです。
</para>
</listitem>
</itemizedlist>
<para>
HQLの <literal>INSERT</literal> 文の実行例です:
HQLの <literal>INSERT</literal> 文の実行例です:
</para>

View File

@ -1,246 +1,248 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="best-practices" revision="3">
<title>ベストプラクティス</title>
<title>ベストプラクティス</title>
<variablelist spacing="compact">
<varlistentry>
<term>
クラスは細かい粒度で書き <literal>&lt;component&gt;</literal> でマッピングしましょう。</term>
クラスは細かい粒度で書き <literal>&lt;component&gt;</literal> でマッピングしましょう。</term>
<listitem>
<para>
<literal>street</literal>(通り), <literal>suburb</literal>
(都市), <literal>state</literal>(州), <literal>postcode</literal>
(郵便番号)をカプセル化する <literal>Address</literal>(住所)クラスを使いましょう。
そうすればコードが再利用しやすくなり、リファクタリングも簡単になります。
<literal>street</literal>(通り), <literal>suburb</literal>
(都市), <literal>state</literal>(州), <literal>postcode</literal>
(郵便番号)をカプセル化する <literal>Address</literal>(住所)クラスを使いましょう。
そうすればコードが再利用しやすくなり、リファクタリングも簡単になります。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
永続クラスには識別子プロパティを定義しましょう。</term>
永続クラスには識別子プロパティを定義しましょう。</term>
<listitem>
<para>
Hibernateでは識別子プロパティはオプションですが、
使用すべき理由がたくさんあります。
識別子は「人工的」(生成された、業務的な意味を持たない)
なものにすることをおすすめします。
Hibernateでは識別子プロパティはオプションですが、
使用すべき理由がたくさんあります。
識別子は「人工的」(生成された、業務的な意味を持たない)
なものにすることをおすすめします。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>自然キーを見つけましょう。</term>
<term>自然キーを見つけましょう。</term>
<listitem>
<para>
すべてのエンティティに対して自然キーを見つけて、
<literal>&lt;natural-id&gt;</literal> でマッピングしましょう。
自然キーを構成するプロパティを比較するために、
<literal>equals()</literal><literal>hashCode()</literal> を実装しましょう。
すべてのエンティティに対して自然キーを見つけて、
<literal>&lt;natural-id&gt;</literal> でマッピングしましょう。
自然キーを構成するプロパティを比較するために、
<literal>equals()</literal><literal>hashCode()</literal> を実装しましょう。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>クラスのマッピングはそれぞれのクラス専用のファイルに書きましょう。</term>
<term>クラスのマッピングはそれぞれのクラス専用のファイルに書きましょう。</term>
<listitem>
<para>
単一の巨大なマッピングドキュメントを使用しないでください。
<literal>com.eg.Foo</literal> クラスなら
<literal>com/eg/Foo.hbm.xml</literal> ファイルにマッピングしましょう。
このことは、特にチームでの開発に意味があります。
単一の巨大なマッピングドキュメントを使用しないでください。
<literal>com.eg.Foo</literal> クラスなら
<literal>com/eg/Foo.hbm.xml</literal> ファイルにマッピングしましょう。
このことは、特にチームでの開発に意味があります。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>リソースとしてマッピングをロードしましょう。</term>
<term>リソースとしてマッピングをロードしましょう。</term>
<listitem>
<para>
マッピングを、それらがマッピングするするクラスと一緒に配置しましょう。
マッピングを、それらがマッピングするするクラスと一緒に配置しましょう。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>クエリ文字列を外部に置くことを考えましょう</term>
<term>クエリ文字列を外部に置くことを考えましょう</term>
<listitem>
<para>
クエリがANSI標準でないSQL関数を呼んでいるなら、これはよいプラクティスです。
クエリ文字列をマッピングファイルへ外出しすればアプリケーションがポータブルになります。
クエリがANSI標準でないSQL関数を呼んでいるなら、これはよいプラクティスです。
クエリ文字列をマッピングファイルへ外出しすればアプリケーションがポータブルになります。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>バインド変数を使いましょう。</term>
<term>バインド変数を使いましょう。</term>
<listitem>
<para>
JDBCの場合と同じように、定数でない値は必ず"?"で置き換えましょう。
定数でない値をバインドするために、クエリで文字列操作を使ってはいけません。
名前付きのパラメータを使うようにするとさらに良いです。
JDBCの場合と同じように、定数でない値は必ず"?"で置き換えましょう。
定数でない値をバインドするために、クエリで文字列操作を使ってはいけません。
名前付きのパラメータを使うようにするとさらに良いです。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>JDBCコネクションを管理してはいけません。</term>
<term>JDBCコネクションを管理してはいけません。</term>
<listitem>
<para>
HibernateではアプリケーションがJDBCコネクションを管理することが許されています。
しかしこれは最終手段だと思ってください。
組み込みのコネクションプロバイダを使うことができなければ、
<literal>org.hibernate.connection.ConnectionProvider</literal> を実装することを考えてください。
HibernateではアプリケーションがJDBCコネクションを管理することが許されています。
しかしこれは最終手段だと思ってください。
組み込みのコネクションプロバイダを使うことができなければ、
<literal>org.hibernate.connection.ConnectionProvider</literal> を実装することを考えてください。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>カスタム型の使用を考えましょう。</term>
<term>カスタム型の使用を考えましょう。</term>
<listitem>
<para>
あるライブラリから持ってきたJava型を永続化する必要があるとしましょう。
しかしその型には、コンポーネントとしてマッピングするために必要なアクセサがないとします。
このような場合は <literal>org.hibernate.UserType</literal> の実装を考えるべきです。
そうすればHibernate型との実装変換を心配せずにアプリケーションのコードを扱えます。
あるライブラリから持ってきたJava型を永続化する必要があるとしましょう。
しかしその型には、コンポーネントとしてマッピングするために必要なアクセサがないとします。
このような場合は <literal>org.hibernate.UserType</literal> の実装を考えるべきです。
そうすればHibernate型との実装変換を心配せずにアプリケーションのコードを扱えます。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>ボトルネックを解消するにはJDBCをハンドコードしましょう。</term>
<term>ボトルネックを解消するにはJDBCをハンドコードしましょう。</term>
<listitem>
<para>
システムのパフォーマンスクリティカルな領域では、
ある種の操作にJDBCを直接使うと良いかもしれません。
しかし何がボトルネックになっているか <emphasis>はっきりする</emphasis> までは待ってください。
またJDBCを直接使うからといって、必ずしも速くなるとは限らないことも理解してください。
JDBCを直接使う必要があれば、Hibernateの <literal>Session</literal> をオープンして、
JDBCコネクションを使うと良いかもしれません。
依然として同じトランザクション戦略とコネクションプロバイダが使えるからです。
システムのパフォーマンスクリティカルな領域では、
ある種の操作にJDBCを直接使うと良いかもしれません。
しかし何がボトルネックになっているか <emphasis>はっきりする</emphasis> までは待ってください。
またJDBCを直接使うからといって、必ずしも速くなるとは限らないことも理解してください。
JDBCを直接使う必要があれば、Hibernateの <literal>Session</literal> をオープンして、
JDBCコネクションを使うと良いかもしれません。
依然として同じトランザクション戦略とコネクションプロバイダが使えるからです。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>Session</literal> のフラッシュを理解しましょう。</term>
<term><literal>Session</literal> のフラッシュを理解しましょう。</term>
<listitem>
<para>
Sessionが永続状態をデータベースと同期させることがときどきあります。
しかしこれがあまりに頻繁に起こるようだと、パフォーマンスに影響が出てきます。
自動フラッシュを無効にしたり、特定のトランザクションのクエリや操作の順番を変更することで、
不必要なフラッシュを最小限にできます。
Sessionが永続状態をデータベースと同期させることがときどきあります。
しかしこれがあまりに頻繁に起こるようだと、パフォーマンスに影響が出てきます。
自動フラッシュを無効にしたり、特定のトランザクションのクエリや操作の順番を変更することで、
不必要なフラッシュを最小限にできます。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>3層アーキテクチャでは分離オブジェクトの使用を考えましょう。</term>
<term>3層アーキテクチャでは分離オブジェクトの使用を考えましょう。</term>
<listitem>
<para>
サーブレット / セッションビーンアーキテクチャを使うとき、
サーブレット層 / JSP層間でセッションビーンでロードした永続オブジェクトをやり取りできます。
その際リクエストごとに新しいSessionを使ってください。
また <literal>Session.merge()</literal><literal>Session.saveOrUpdate()</literal>
を使って、オブジェクトとデータベースを同期させてください。
サーブレット / セッションビーンアーキテクチャを使うとき、
サーブレット層 / JSP層間でセッションビーンでロードした永続オブジェクトをやり取りできます。
その際リクエストごとに新しいSessionを使ってください。
また <literal>Session.merge()</literal><literal>Session.saveOrUpdate()</literal>
を使って、オブジェクトとデータベースを同期させてください。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>2層アーキテクチャでは長い永続コンテキストの使用を考えましょう。</term>
<term>2層アーキテクチャでは長い永続コンテキストの使用を考えましょう。</term>
<listitem>
<para>
最高のスケーラビリティを得るには、
データベーストランザクションをできるだけ短くしなければなりません。
しかし長い間実行する <emphasis>アプリケーショントランザクション</emphasis>
の実装が必要なことはしばしばです。
これはユーザの視点からは1個の作業単位unit of workになります。
アプリケーショントランザクションはいくつかのクライアントのリクエスト/レスポンスサイクルにまたがります。
アプリケーショントランザクションの実装に分離オブジェクトを使うのは一般的です。
最高のスケーラビリティを得るには、
データベーストランザクションをできるだけ短くしなければなりません。
しかし長い間実行する <emphasis>アプリケーショントランザクション</emphasis>
の実装が必要なことはしばしばです。
これはユーザの視点からは1個の作業単位unit of workになります。
アプリケーショントランザクションはいくつかのクライアントのリクエスト/レスポンスサイクルにまたがります。
アプリケーショントランザクションの実装に分離オブジェクトを使うのは一般的です。
そうでなければ、2層アーキテクチャの場合は特に適切なことですが、
アプリケーショントランザクションのライフサイクル全体に対して
単一のオープンな永続化コンテキスト(セッション)を維持してください。
そして単純にリクエストの最後にJDBCコネクションから切断し、
次のリクエストの最初に再接続します。
そうでなければ、2層アーキテクチャの場合は特に適切なことですが、
アプリケーショントランザクションのライフサイクル全体に対して
単一のオープンな永続化コンテキスト(セッション)を維持してください。
そして単純にリクエストの最後にJDBCコネクションから切断し、
次のリクエストの最初に再接続します。
決して複数のアプリケーショントランザクションユースケースに渡って
1個のSessionを使い回さないでください。
そうでなければ、古いデータで作業することになります。
決して複数のアプリケーショントランザクションユースケースに渡って
1個のSessionを使い回さないでください。
そうでなければ、古いデータで作業することになります。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>例外を復帰可能なものとして扱ってはいけません。</term>
<term>例外を復帰可能なものとして扱ってはいけません。</term>
<listitem>
<para>
これは「ベスト」プラクティス以上の、必須のプラクティスです。
例外が発生したときは <literal>Transaction</literal> をロールバックして、
<literal>Session</literal> をクローズしてください。
そうしないとHibernateはメモリの状態が永続状態を正確に表現していることを保証できません。
この特別な場合として、与えられた識別子を持つインスタンスがデータベースに存在するかどうかを判定するために、
<literal>Session.load()</literal> を使うことはやめてください。
その代わりに <literal>Session.get()</literal> かクエリを使ってください。
これは「ベスト」プラクティス以上の、必須のプラクティスです。
例外が発生したときは <literal>Transaction</literal> をロールバックして、
<literal>Session</literal> をクローズしてください。
そうしないとHibernateはメモリの状態が永続状態を正確に表現していることを保証できません。
この特別な場合として、与えられた識別子を持つインスタンスがデータベースに存在するかどうかを判定するために、
<literal>Session.load()</literal> を使うことはやめてください。
その代わりに <literal>Session.get()</literal> かクエリを使ってください。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>関連にはなるべく遅延フェッチを使いましょう。</term>
<term>関連にはなるべく遅延フェッチを使いましょう。</term>
<listitem>
<para>
即時フェッチは控えめにしましょう。
二次キャッシュには完全に保持されないようなクラスの関連には、
プロキシと遅延コレクションを使ってください。
キャッシュされるクラスの関連、つまりキャッシュがヒットする可能性が非常に高い関連は、
<literal>lazy="false"</literal> で積極的なフェッチを明示的に無効にしてください。
結合フェッチが適切な特定のユースケースには、
クエリで <literal>left join fetch</literal> を使ってください。
即時フェッチは控えめにしましょう。
二次キャッシュには完全に保持されないようなクラスの関連には、
プロキシと遅延コレクションを使ってください。
キャッシュされるクラスの関連、つまりキャッシュがヒットする可能性が非常に高い関連は、
<literal>lazy="false"</literal> で積極的なフェッチを明示的に無効にしてください。
結合フェッチが適切な特定のユースケースには、
クエリで <literal>left join fetch</literal> を使ってください。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
フェッチされていないデータに関わる問題を避けるために、
<emphasis>ビューの中でオープンセッションを使う(open session in view)</emphasis>
パターンか、統制された <emphasis>組み立てフェーズ(assembly phase)</emphasis> を使いましょう。
フェッチされていないデータに関わる問題を避けるために、
<emphasis>ビューの中でオープンセッションを使う(open session in view)</emphasis>
パターンか、統制された <emphasis>組み立てフェーズ(assembly phase)</emphasis> を使いましょう。
</term>
<listitem>
<para>
Hibernateは <emphasis>Data Transfer Objects</emphasis> (DTO)を書く退屈な作業から開発者を解放します。
伝統的なEJBアーキテクチャではDTOは二つ目的があります
1つ目は、エンティティビーンがシリアライズされない問題への対策です。
2つ目は、プレゼンテーション層に制御が戻る前に、
ビューに使われるすべてのデータがフェッチされて、DTOに復元されるような組み立てフェーズを暗黙的に定義します。
Hibernateでは1つ目の目的が不要になります。
しかしビューのレンダリング処理の間、永続コンテキスト(セッション)をオープンにしたままにしなければ、
組み立てフェーズはまだ必要です(分離オブジェクトの中のどのデータが利用可能かについて、
プレゼンテーション層と厳密な取り決めをしているビジネスメソッドを考えてみてください)。
これはHibernate側の問題ではありません。
トランザクション内で安全にデータアクセスするための基本的な要件です。
Hibernateは <emphasis>Data Transfer Objects</emphasis> (DTO)を書く退屈な作業から開発者を解放します。
伝統的なEJBアーキテクチャではDTOは二つ目的があります
1つ目は、エンティティビーンがシリアライズされない問題への対策です。
2つ目は、プレゼンテーション層に制御が戻る前に、
ビューに使われるすべてのデータがフェッチされて、DTOに復元されるような組み立てフェーズを暗黙的に定義します。
Hibernateでは1つ目の目的が不要になります。
しかしビューのレンダリング処理の間、永続コンテキスト(セッション)をオープンにしたままにしなければ、
組み立てフェーズはまだ必要です(分離オブジェクトの中のどのデータが利用可能かについて、
プレゼンテーション層と厳密な取り決めをしているビジネスメソッドを考えてみてください)。
これはHibernate側の問題ではありません。
トランザクション内で安全にデータアクセスするための基本的な要件です。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Hibernateからビジネスロジックを抽象化することを考えましょう。</term>
<term>Hibernateからビジネスロジックを抽象化することを考えましょう。</term>
<listitem>
<para>
インターフェイスでHibernateのデータアクセスコードを隠蔽しましょう。
<emphasis>DAO</emphasis><emphasis>Thread Local Session</emphasis> パターンを組み合わせましょう。
<literal>UserType</literal> でHibernateに関連付けると、
ハンドコードしたJDBCで永続化するクラスを持つこともできます。
(このアドバイスは「十分大きな」アプリケーションに対してのものです。
テーブルが5個しかないようなアプリケーションには当てはまりません。
インターフェイスでHibernateのデータアクセスコードを隠蔽しましょう。
<emphasis>DAO</emphasis><emphasis>Thread Local Session</emphasis> パターンを組み合わせましょう。
<literal>UserType</literal> でHibernateに関連付けると、
ハンドコードしたJDBCで永続化するクラスを持つこともできます。
(このアドバイスは「十分大きな」アプリケーションに対してのものです。
テーブルが5個しかないようなアプリケーションには当てはまりません。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>珍しい関連マッピングは使わないようにしましょう。</term>
<term>珍しい関連マッピングは使わないようにしましょう。</term>
<listitem>
<para>
よいユースケースに本当の多対多関連があることは稀(まれ)です。
ほとんどの場合「リンクテーブル」の付加的な情報が必要になります。
この場合、リンククラスに2つの1対多関連を使う方がずっと良いです。
実際ほとんどの場合関連は1対多と多対1なので、
他のスタイルの関連を使うときは本当に必要かどうかを考えてみてください。
よいユースケースに本当の多対多関連があることは稀(まれ)です。
ほとんどの場合「リンクテーブル」の付加的な情報が必要になります。
この場合、リンククラスに2つの1対多関連を使う方がずっと良いです。
実際ほとんどの場合関連は1対多と多対1なので、
他のスタイルの関連を使うときは本当に必要かどうかを考えてみてください。
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>なるべく双方向関連にしましょう。</term>
<term>なるべく双方向関連にしましょう。</term>
<listitem>
<para>
単方向関連は双方向に比べて検索が難しくなります。
大きなアプリケーションでは、
ほとんどすべての関連が双方向にナビゲーションできなければなりません。
単方向関連は双方向に比べて検索が難しくなります。
大きなアプリケーションでは、
ほとんどすべての関連が双方向にナビゲーションできなければなりません。
</para>
</listitem>
</varlistentry>

View File

@ -1,20 +1,22 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="components">
<title>コンポーネントのマッピング</title>
<title>コンポーネントのマッピング</title>
<para>
<emphasis>コンポーネント</emphasis> の概念は、Hibernateを通して様々な状況の中で
異なる目的のために再利用されます。
<emphasis>コンポーネント</emphasis> の概念は、Hibernateを通して様々な状況の中で
異なる目的のために再利用されます。
</para>
<sect1 id="components-dependentobjects" revision="2" >
<title>依存オブジェクト</title>
<title>依存オブジェクト</title>
<para>
コンポーネントは、エンティティの参照ではなく値型として永続化された、
包含されたオブジェクトです。コンポーネントという言葉については、コンポジションという
オブジェクト指向の概念を参照してください(アーキテクチャレベルのコンポーネントではありません)。
例えば、以下のPersonモデルのようなものです。
コンポーネントは、エンティティの参照ではなく値型として永続化された、
包含されたオブジェクトです。コンポーネントという言葉については、コンポジションという
オブジェクト指向の概念を参照してください(アーキテクチャレベルのコンポーネントではありません)。
例えば、以下のPersonモデルのようなものです。
</para>
<programlisting><![CDATA[public class Person {
@ -68,14 +70,14 @@
}]]></programlisting>
<para>
いま、<literal>Name</literal><literal>Person</literal> のコンポーネントとして
永続化することが出来ます。ここで <literal>Name</literal> は永続化属性に対してgetter、
setterメソッドを定義しますが、インターフェイスや識別子プロパティを定義する必要が
ないことに注意して下さい。
いま、<literal>Name</literal><literal>Person</literal> のコンポーネントとして
永続化することが出来ます。ここで <literal>Name</literal> は永続化属性に対してgetter、
setterメソッドを定義しますが、インターフェイスや識別子プロパティを定義する必要が
ないことに注意して下さい。
</para>
<para>
マッピング定義は以下のようになります。
マッピング定義は以下のようになります。
</para>
<programlisting><![CDATA[<class name="eg.Person" table="person">
@ -91,33 +93,33 @@
</class>]]></programlisting>
<para>
Personテーブルは <literal>pid</literal>
<literal>birthday</literal>
<literal>initial</literal>
<literal>first</literal>
<literal>last</literal> カラムを持ちます。
Personテーブルは <literal>pid</literal>
<literal>birthday</literal>
<literal>initial</literal>
<literal>first</literal>
<literal>last</literal> カラムを持ちます。
</para>
<para>
全ての値型のように、コンポーネントは参照の共有をすることができません。
言い換えると、二人のPersonは同じ名前を持つことができますが、二つのPersonオブジェクトは
"値が同じだけ"の別々のnameオブジェクトを含んでいるということです。
コンポーネントのnull値のセマンティクスは <emphasis>アドホック</emphasis> です。
コンポーネントのオブジェクトを再読み込みする際、Hibernateはコンポーネントのすべてのカラムが
nullであるならコンポーネント自体がnullであると考えます。
これは大抵の場合問題ありません。
全ての値型のように、コンポーネントは参照の共有をすることができません。
言い換えると、二人のPersonは同じ名前を持つことができますが、二つのPersonオブジェクトは
"値が同じだけ"の別々のnameオブジェクトを含んでいるということです。
コンポーネントのnull値のセマンティクスは <emphasis>アドホック</emphasis> です。
コンポーネントのオブジェクトを再読み込みする際、Hibernateはコンポーネントのすべてのカラムが
nullであるならコンポーネント自体がnullであると考えます。
これは大抵の場合問題ありません。
</para>
<para>
コンポーネントの属性はどんなHibernateの型でも構いませんコレクション、many-to-one関連、
他のコンポーネントなど)。ネストされたコンポーネントは滅多に使わないと考えるべきでは
<emphasis>ありません</emphasis> 。Hibernateは非常にきめの細かいオブジェクトモデルをサポートするように意図されています。
コンポーネントの属性はどんなHibernateの型でも構いませんコレクション、many-to-one関連、
他のコンポーネントなど)。ネストされたコンポーネントは滅多に使わないと考えるべきでは
<emphasis>ありません</emphasis> 。Hibernateは非常にきめの細かいオブジェクトモデルをサポートするように意図されています。
</para>
<para>
<literal>&lt;component&gt;</literal> 要素は親エンティティへの逆参照として、コンポーネントクラスの
属性をマッピングする <literal>&lt;parent&gt;</literal> サブ要素を使用できます。
<literal>&lt;component&gt;</literal> 要素は親エンティティへの逆参照として、コンポーネントクラスの
属性をマッピングする <literal>&lt;parent&gt;</literal> サブ要素を使用できます。
</para>
<programlisting><![CDATA[<class name="eg.Person" table="person">
@ -137,12 +139,12 @@
<sect1 id="components-incollections" revision="1">
<title>従属するオブジェクトのコレクション</title>
<title>従属するオブジェクトのコレクション</title>
<para>
Hibernateはコンポーネントのコレクションをサポートしています例えば <literal>Name</literal> 型の配列)。
<literal>&lt;element&gt;</literal> タグを <literal>&lt;composite-element&gt;</literal> タグに取り替えることにより
コンポーネントコレクションを宣言してください。
Hibernateはコンポーネントのコレクションをサポートしています例えば <literal>Name</literal> 型の配列)。
<literal>&lt;element&gt;</literal> タグを <literal>&lt;composite-element&gt;</literal> タグに取り替えることにより
コンポーネントコレクションを宣言してください。
</para>
<programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
@ -155,35 +157,35 @@
</set>]]></programlisting>
<para>
注意: コンポジットエレメントの <literal>Set</literal> を定義したなら、
<literal>equals()</literal><literal>hashCode()</literal> を正しく実装することが重要です。
注意: コンポジットエレメントの <literal>Set</literal> を定義したなら、
<literal>equals()</literal><literal>hashCode()</literal> を正しく実装することが重要です。
</para>
<para>
コンポジットエレメントはコレクションを含まず、コンポーネントを含むこともあります。
コンポジットエレメント自身がコンポーネントを含んでいる場合は <literal>&lt;nested-composite-element&gt;</literal>
使用してください。コンポーネントのコレクション自身がコンポーネントを持つというケースはめったにありません。
この段階までに、one-to-many関連の方がより適切でないかと熟考してください。
コンポジットエレメントをエンティティとして再度モデリングしてみてください。
しかしこれはJavaのモデルとしては同じですが、リレーショナルモデルと永続動作はまだ若干異なることに注意してください。
コンポジットエレメントはコレクションを含まず、コンポーネントを含むこともあります。
コンポジットエレメント自身がコンポーネントを含んでいる場合は <literal>&lt;nested-composite-element&gt;</literal>
使用してください。コンポーネントのコレクション自身がコンポーネントを持つというケースはめったにありません。
この段階までに、one-to-many関連の方がより適切でないかと熟考してください。
コンポジットエレメントをエンティティとして再度モデリングしてみてください。
しかしこれはJavaのモデルとしては同じですが、リレーショナルモデルと永続動作はまだ若干異なることに注意してください。
</para>
<para>
もし <literal>&lt;set&gt;</literal> を使用するのであれば、コンポジットエレメントのマッピングがnull値が可能な
属性をサポートしていないことに注意してください。Hibernateはオブジェクトを削除するとき、
レコードを識別するためにそれぞれのカラムの値を使用する必要があるため、null値を持つことが出来ません
(コンポジットエレメントテーブルには別の主キーカラムはありません)。
コンポジットエレメントにnot-nullの属性のみを使用するか、または <literal>&lt;list&gt;</literal><literal>&lt;map&gt;</literal>
<literal>&lt;bag&gt;</literal><literal>&lt;idbag&gt;</literal> を選択する必要があります。
もし <literal>&lt;set&gt;</literal> を使用するのであれば、コンポジットエレメントのマッピングがnull値が可能な
属性をサポートしていないことに注意してください。Hibernateはオブジェクトを削除するとき、
レコードを識別するためにそれぞれのカラムの値を使用する必要があるため、null値を持つことが出来ません
(コンポジットエレメントテーブルには別の主キーカラムはありません)。
コンポジットエレメントにnot-nullの属性のみを使用するか、または <literal>&lt;list&gt;</literal><literal>&lt;map&gt;</literal>
<literal>&lt;bag&gt;</literal><literal>&lt;idbag&gt;</literal> を選択する必要があります。
</para>
<para>
コンポジットエレメントの特別なケースとして、ネストされた <literal>&lt;many-to-one&gt;</literal> 属性を持つ
コンポジットエレメントがあります。
このマッピングは、コンポジットエレメントクラスを多対多関連テーブルの
余分なカラムへマッピングします。
次の例は <literal>Order</literal> から、<literal>Item</literal> への多対多関連です。
<literal>purchaseDate</literal><literal>price</literal><literal>quantity</literal> は関連の属性となります。
コンポジットエレメントの特別なケースとして、ネストされた <literal>&lt;many-to-one&gt;</literal> 属性を持つ
コンポジットエレメントがあります。
このマッピングは、コンポジットエレメントクラスを多対多関連テーブルの
余分なカラムへマッピングします。
次の例は <literal>Order</literal> から、<literal>Item</literal> への多対多関連です。
<literal>purchaseDate</literal><literal>price</literal><literal>quantity</literal> は関連の属性となります。
</para>
<programlisting><![CDATA[<class name="eg.Order" .... >
@ -200,14 +202,14 @@
</class>]]></programlisting>
<para>
もちろん、双方向関連のナビゲーションのために反対側からpurchaseへの参照を作ることは出来ません。
コンポーネントは値型であり、参照を共有できないことを覚えておいてください。
一つの <literal>Purchase</literal> は一つの <literal>Order</literal> のsetに存在できますが、
同時に <literal>Item</literal> から参照することは出来ません。
もちろん、双方向関連のナビゲーションのために反対側からpurchaseへの参照を作ることは出来ません。
コンポーネントは値型であり、参照を共有できないことを覚えておいてください。
一つの <literal>Purchase</literal> は一つの <literal>Order</literal> のsetに存在できますが、
同時に <literal>Item</literal> から参照することは出来ません。
</para>
<para>
3項関連あるいは4項なども可能です。
3項関連あるいは4項なども可能です。
</para>
<programlisting><![CDATA[<class name="eg.Order" .... >
@ -222,61 +224,61 @@
</class>]]></programlisting>
<para>
コンポジットエレメントは他のエンティティへの関連として、
同じシンタックスを使っているクエリ内で使用できます。
コンポジットエレメントは他のエンティティへの関連として、
同じシンタックスを使っているクエリ内で使用できます。
</para>
</sect1>
<sect1 id="components-asmapindex">
<title>Mapのインデックスとしてのコンポーネント</title>
<title>Mapのインデックスとしてのコンポーネント</title>
<para>
<literal>&lt;composite-map-key&gt;</literal> 要素は <literal>Map</literal> のキーとしてコンポーネントクラスを
マッピングします。コンポーネントクラス上で <literal>hashCode()</literal><literal>equals()</literal>
を正確にオーバーライドしてください。
<literal>&lt;composite-map-key&gt;</literal> 要素は <literal>Map</literal> のキーとしてコンポーネントクラスを
マッピングします。コンポーネントクラス上で <literal>hashCode()</literal><literal>equals()</literal>
を正確にオーバーライドしてください。
</para>
</sect1>
<sect1 id="components-compositeid" revision="1">
<title>複合識別子としてのコンポーネント</title>
<title>複合識別子としてのコンポーネント</title>
<para>
コンポーネントをエンティティクラスの識別子として使うことができます。
コンポーネントクラスは以下の条件を満たす必要があります。
コンポーネントをエンティティクラスの識別子として使うことができます。
コンポーネントクラスは以下の条件を満たす必要があります。
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
<literal>java.io.Serializable</literal> を実装しなければなりません。
<literal>java.io.Serializable</literal> を実装しなければなりません。
</para>
</listitem>
<listitem>
<para>
データベース上の複合キーの等価性と矛盾のないように、<literal>equals()</literal>
<literal>hashCode()</literal> を再実装しなければなりません。
データベース上の複合キーの等価性と矛盾のないように、<literal>equals()</literal>
<literal>hashCode()</literal> を再実装しなければなりません。
</para>
</listitem>
</itemizedlist>
<para>
<emphasis>注意: Hibernate3において、2番目の条件は絶対的な条件ではありません。
しかしとにかく条件を満たしてください。
<emphasis>注意: Hibernate3において、2番目の条件は絶対的な条件ではありません。
しかしとにかく条件を満たしてください。
</emphasis>
</para>
<para>
複合キーを生成するために <literal>IdentifierGenerator</literal> を使用することはできません。
代わりにアプリケーションが識別子を割り当てなくてはなりません。
複合キーを生成するために <literal>IdentifierGenerator</literal> を使用することはできません。
代わりにアプリケーションが識別子を割り当てなくてはなりません。
</para>
<para>
通常の <literal>&lt;id&gt;</literal> 宣言の代わりに <literal>&lt;composite-id&gt;</literal> タグを
(ネストされた <literal>&lt;key-property&gt;</literal> 属性と共に)使います。
以下の例では、<literal>OrderLine</literal> クラスは <literal>Order</literal> の(複合)主キーに
依存した主キーを持っています。
通常の <literal>&lt;id&gt;</literal> 宣言の代わりに <literal>&lt;composite-id&gt;</literal> タグを
(ネストされた <literal>&lt;key-property&gt;</literal> 属性と共に)使います。
以下の例では、<literal>OrderLine</literal> クラスは <literal>Order</literal> の(複合)主キーに
依存した主キーを持っています。
</para>
<programlisting><![CDATA[<class name="OrderLine">
@ -299,9 +301,9 @@
</class>]]></programlisting>
<para>
このとき、<literal>OrderLine</literal> テーブルへ関連する外部キーもまた複合です。
他のクラスのマッピングでこれを宣言しなければなりません。
<literal>OrderLine</literal> への関連は次のようにマッピングされます。
このとき、<literal>OrderLine</literal> テーブルへ関連する外部キーもまた複合です。
他のクラスのマッピングでこれを宣言しなければなりません。
<literal>OrderLine</literal> への関連は次のようにマッピングされます。
</para>
<programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
@ -312,13 +314,13 @@
</many-to-one>]]></programlisting>
<para>
<literal>&lt;column&gt;</literal> タグはどこであっても <literal>column</literal> 属性の
代わりになります。)
<literal>&lt;column&gt;</literal> タグはどこであっても <literal>column</literal> 属性の
代わりになります。)
</para>
<para>
<literal>OrderLine</literal> への <literal>many-to-many</literal> 関連も
複合外部キーを使います。
<literal>OrderLine</literal> への <literal>many-to-many</literal> 関連も
複合外部キーを使います。
</para>
<programlisting><![CDATA[<set name="undeliveredOrderLines">
@ -331,8 +333,8 @@
</set>]]></programlisting>
<para>
<literal>Order</literal> にある <literal>OrderLine</literal> のコレクションは
次のものを使用します。
<literal>Order</literal> にある <literal>OrderLine</literal> のコレクションは
次のものを使用します。
</para>
<programlisting><![CDATA[<set name="orderLines" inverse="true">
@ -344,12 +346,12 @@
</set>]]></programlisting>
<para>
<literal>&lt;one-to-many&gt;</literal> 属性は、例によってカラムを宣言しません)
<literal>&lt;one-to-many&gt;</literal> 属性は、例によってカラムを宣言しません)
</para>
<para>
<literal>OrderLine</literal> 自身がコレクションを持っている場合、
同時に複合外部キーも持っています。
<literal>OrderLine</literal> 自身がコレクションを持っている場合、
同時に複合外部キーも持っています。
</para>
<programlisting><![CDATA[<class name="OrderLine">
@ -371,10 +373,10 @@
</sect1>
<sect1 id="components-dynamic" revision="1">
<title>動的コンポーネント</title>
<title>動的コンポーネント</title>
<para>
<literal>Map</literal> 型のプロパティのマッピングも可能です。
<literal>Map</literal> 型のプロパティのマッピングも可能です。
</para>
<programlisting><![CDATA[<dynamic-component name="userAttributes">
@ -384,11 +386,11 @@
</dynamic-component>]]></programlisting>
<para>
<literal>&lt;dynamic-component&gt;</literal> マッピングのセマンティクスは <literal>&lt;component&gt;</literal>
と同一のものです。この種のマッピングの利点は、マッピングドキュメントの編集により、配置時にbeanの属性を
決定できる点です。また、DOMパーサを利用して、マッピングドキュメントのランタイム操作が可能です。
さらに、<literal>Configuration</literal> オブジェクト経由でHibernateのコンフィグレーション時のメタモデルに
アクセス(または変更)が可能です。
<literal>&lt;dynamic-component&gt;</literal> マッピングのセマンティクスは <literal>&lt;component&gt;</literal>
と同一のものです。この種のマッピングの利点は、マッピングドキュメントの編集により、配置時にbeanの属性を
決定できる点です。また、DOMパーサを利用して、マッピングドキュメントのランタイム操作が可能です。
さらに、<literal>Configuration</literal> オブジェクト経由でHibernateのコンフィグレーション時のメタモデルに
アクセス(または変更)が可能です。
</para>
</sect1>

View File

@ -1,31 +1,33 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="events">
<title>インターセプタとイベント</title>
<title>インターセプタとイベント</title>
<para>
アプリケーションがHibernateの内部で発生するイベントに対応できると役に立つことがあります。
ある種の一般的な機能を実装できるようになり、
またHibernateの機能を拡張することもできるようになります。
アプリケーションがHibernateの内部で発生するイベントに対応できると役に立つことがあります。
ある種の一般的な機能を実装できるようになり、
またHibernateの機能を拡張することもできるようになります。
</para>
<sect1 id="objectstate-interceptors" revision="3">
<title>インターセプタ</title>
<title>インターセプタ</title>
<para>
<literal>Interceptor</literal> インターフェイスを使って、
セッションからアプリケーションへコールバックをすることができます。
これにより永続オブジェクトの保存、更新、削除、読み込みの前に、
アプリケーションがプロパティを検査したり操作したりできるようになります。
これは監査情報の追跡に利用できます。
下の例で <literal>Interceptor</literal><literal>Auditable</literal>
が作成されると自動的に <literal>createTimestamp</literal> を設定し、
<literal>Auditable</literal> が更新されると自動的に
<literal>lastUpdateTimestamp</literal> プロパティを更新します。
<literal>Interceptor</literal> インターフェイスを使って、
セッションからアプリケーションへコールバックをすることができます。
これにより永続オブジェクトの保存、更新、削除、読み込みの前に、
アプリケーションがプロパティを検査したり操作したりできるようになります。
これは監査情報の追跡に利用できます。
下の例で <literal>Interceptor</literal><literal>Auditable</literal>
が作成されると自動的に <literal>createTimestamp</literal> を設定し、
<literal>Auditable</literal> が更新されると自動的に
<literal>lastUpdateTimestamp</literal> プロパティを更新します。
</para>
<para>
<literal>Interceptor</literal> を直接実装したり、
(さらによいのは)<literal>EmptyInterceptor</literal> を拡張したりできます。
<literal>Interceptor</literal> を直接実装したり、
(さらによいのは)<literal>EmptyInterceptor</literal> を拡張したりできます。
</para>
<programlisting><![CDATA[package org.hibernate.test;
@ -112,30 +114,30 @@ public class AuditInterceptor extends EmptyInterceptor {
}]]></programlisting>
<para>
インターセプタには二種類あります:
<literal>Session</literal> スコープのものと
<literal>SessionFactory</literal> スコープのものです。
インターセプタには二種類あります:
<literal>Session</literal> スコープのものと
<literal>SessionFactory</literal> スコープのものです。
</para>
<para>
<literal>Session</literal> スコープのインターセプタは、
セッションをオープンするときに指定します。
<literal>Interceptor</literal> を引数に取るSessionFactory.openSession()
のオーバーロードメソッドの一つを使います。
<literal>Session</literal> スコープのインターセプタは、
セッションをオープンするときに指定します。
<literal>Interceptor</literal> を引数に取るSessionFactory.openSession()
のオーバーロードメソッドの一つを使います。
</para>
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
<para>
<literal>SessionFactory</literal> スコープのインターセプタは <literal>Configuration</literal>
オブジェクトを使って登録します。
これは <literal>SessionFactory</literal> の構築よりも優先されます。
この場合、提供されるインターセプタは <literal>SessionFactory</literal>
からオープンされたすべてのセッションに適用されます。
これは使用するインターセプタを明示的に指定してセッションをオープンしない限り、そうなります。
<literal>SessionFactory</literal> スコープのインターセプタはスレッドセーフでなければなりません。
複数のセッションが(潜在的に)このインターセプタを同時並行で使用することになるため、
セッション固有の状態を格納しないように気をつけてください。
<literal>SessionFactory</literal> スコープのインターセプタは <literal>Configuration</literal>
オブジェクトを使って登録します。
これは <literal>SessionFactory</literal> の構築よりも優先されます。
この場合、提供されるインターセプタは <literal>SessionFactory</literal>
からオープンされたすべてのセッションに適用されます。
これは使用するインターセプタを明示的に指定してセッションをオープンしない限り、そうなります。
<literal>SessionFactory</literal> スコープのインターセプタはスレッドセーフでなければなりません。
複数のセッションが(潜在的に)このインターセプタを同時並行で使用することになるため、
セッション固有の状態を格納しないように気をつけてください。
</para>
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
@ -143,46 +145,46 @@ public class AuditInterceptor extends EmptyInterceptor {
</sect1>
<sect1 id="objectstate-events" revision="4">
<title>イベントシステム</title>
<title>イベントシステム</title>
<para>
永続化層で特定のイベントに対応しなければならない場合、
Hibernate3の <emphasis>イベント</emphasis> アーキテクチャを使うこともできます。
イベントシステムはインターセプタと一緒に使うか、またはインターセプタの代わりとして使うことができます。
永続化層で特定のイベントに対応しなければならない場合、
Hibernate3の <emphasis>イベント</emphasis> アーキテクチャを使うこともできます。
イベントシステムはインターセプタと一緒に使うか、またはインターセプタの代わりとして使うことができます。
</para>
<para>
本質的に <literal>Session</literal> インターフェイスのすべてのメソッドは、
1個のイベントと相互に関連します。
例えば <literal>LoadEvent</literal><literal>FlushEvent</literal> などがあります
定義済みのイベント型の一覧については、XML設定ファイルのDTDや
<literal>org.hibernate.event</literal> パッケージを調べてください)。
リクエストがこれらのメソッドの1つから作られるとき、
Hibernateの <literal>Session</literal> は適切なイベントを生成し、
そのイベント型に設定されたイベントリスナに渡します。
すばらしいことに、これらのリスナはそのメソッドと同じ処理を実装します。
とはいえ、リスナインターフェイスの一つを自由にカスタム実装できます
(つまり、<literal>LoadEvent</literal> は登録された <literal>LoadEventListener</literal>
インターフェイスの実装により処理されます)。
その場合、その実装には <literal>Session</literal> から作られたどのような <literal>load()</literal>
リクエストをも処理する責任があります。
本質的に <literal>Session</literal> インターフェイスのすべてのメソッドは、
1個のイベントと相互に関連します。
例えば <literal>LoadEvent</literal><literal>FlushEvent</literal> などがあります
定義済みのイベント型の一覧については、XML設定ファイルのDTDや
<literal>org.hibernate.event</literal> パッケージを調べてください)。
リクエストがこれらのメソッドの1つから作られるとき、
Hibernateの <literal>Session</literal> は適切なイベントを生成し、
そのイベント型に設定されたイベントリスナに渡します。
すばらしいことに、これらのリスナはそのメソッドと同じ処理を実装します。
とはいえ、リスナインターフェイスの一つを自由にカスタム実装できます
(つまり、<literal>LoadEvent</literal> は登録された <literal>LoadEventListener</literal>
インターフェイスの実装により処理されます)。
その場合、その実装には <literal>Session</literal> から作られたどのような <literal>load()</literal>
リクエストをも処理する責任があります。
</para>
<para>
リスナは事実上シングルトンであると見なせます。
つまりリスナはリクエスト間で共有されるため、
インスタンス変数として状態を保持するべきではないということです。
リスナは事実上シングルトンであると見なせます。
つまりリスナはリクエスト間で共有されるため、
インスタンス変数として状態を保持するべきではないということです。
</para>
<para>
カスタムリスナは処理したいイベントについて適切なインターフェイスを実装するべきです。
便利な基底クラスのうちの一つを継承してもよいです
またはHibernateがデフォルトで使用するイベントリスナを継承してもよいです。
すばらしいことに、この目的のために非finalとして宣言されています
カスタムリスナは <literal>Configuration</literal> オブジェクトを使ってプログラムから登録するか、
HibernateのXML設定ファイルで指定できます
(プロパティファイルで宣言的に設定する方法はサポートされていません)。
カスタムロードイベントリスナの例を示します。
カスタムリスナは処理したいイベントについて適切なインターフェイスを実装するべきです。
便利な基底クラスのうちの一つを継承してもよいです
またはHibernateがデフォルトで使用するイベントリスナを継承してもよいです。
すばらしいことに、この目的のために非finalとして宣言されています
カスタムリスナは <literal>Configuration</literal> オブジェクトを使ってプログラムから登録するか、
HibernateのXML設定ファイルで指定できます
(プロパティファイルで宣言的に設定する方法はサポートされていません)。
カスタムロードイベントリスナの例を示します。
</para>
<programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
@ -196,7 +198,7 @@ public class AuditInterceptor extends EmptyInterceptor {
}]]></programlisting>
<para>
デフォルトリスナ以外のリスナを使うには、Hibernateへの設定も必要です
デフォルトリスナ以外のリスナを使うには、Hibernateへの設定も必要です
</para>
<programlisting><![CDATA[<hibernate-configuration>
@ -210,7 +212,7 @@ public class AuditInterceptor extends EmptyInterceptor {
</hibernate-configuration>]]></programlisting>
<para>
またその他に、プログラムで登録する方法もあります:
またその他に、プログラムで登録する方法もあります:
</para>
<programlisting><![CDATA[Configuration cfg = new Configuration();
@ -218,31 +220,31 @@ LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener
cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
<para>
リスナを宣言的に登録すると、そのリスナのインスタンスを共有できません。
複数の <literal>&lt;listener/&gt;</literal> 要素で同じクラス名が使われると、
それぞれの参照はそのクラスの別々のインスタンスを指すことになります。
リスナ型の間でリスナインスタンスを共有する必要があれば、
プログラムで登録する方法を採らなければなりません。
リスナを宣言的に登録すると、そのリスナのインスタンスを共有できません。
複数の <literal>&lt;listener/&gt;</literal> 要素で同じクラス名が使われると、
それぞれの参照はそのクラスの別々のインスタンスを指すことになります。
リスナ型の間でリスナインスタンスを共有する必要があれば、
プログラムで登録する方法を採らなければなりません。
</para>
<para>
なぜインターフェイスを実装して、特化した型を設定時に指定するのでしょうか?
リスナの実装クラスに、複数のイベントリスナインターフェイスを実装できるからです。
登録時に追加で型を指定することで、カスタムリスナのon/offを設定時に簡単に切り替えられます。
なぜインターフェイスを実装して、特化した型を設定時に指定するのでしょうか?
リスナの実装クラスに、複数のイベントリスナインターフェイスを実装できるからです。
登録時に追加で型を指定することで、カスタムリスナのon/offを設定時に簡単に切り替えられます。
</para>
</sect1>
<sect1 id="objectstate-decl-security" revision="2">
<title>Hibernateの宣言的なセキュリティ</title>
<title>Hibernateの宣言的なセキュリティ</title>
<para>
一般的にHibernateアプリケーションの宣言的なセキュリティは、セッションファサード層で管理します。
現在、Hiberenate3はJACCで許可しかつ、JAASで認証したアクションを許しています。
これはイベントアーキテクチャの最上位に組み込まれているオプションの機能です。
一般的にHibernateアプリケーションの宣言的なセキュリティは、セッションファサード層で管理します。
現在、Hiberenate3はJACCで許可しかつ、JAASで認証したアクションを許しています。
これはイベントアーキテクチャの最上位に組み込まれているオプションの機能です。
</para>
<para>
まず最初に、適切なイベントリスナを設定してJAAS認証を使えるようにしなければなりません。
まず最初に、適切なイベントリスナを設定してJAAS認証を使えるようにしなければなりません。
</para>
<programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
@ -251,21 +253,21 @@ cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
<para>
特定のイベント型に対してちょうど一つのリスナがあるとき、
特定のイベント型に対してちょうど一つのリスナがあるとき、
<literal>&lt;listener type="..." class="..."/&gt;</literal>
<literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>
の簡略形に過ぎないことに注意してください。
<literal>&lt;event type="..."&gt;&lt;listener class="..."/&gt;&lt;/event&gt;</literal>
の簡略形に過ぎないことに注意してください。
</para>
<para>
次に、同じく <literal>hibernate.cfg.xml</literal> でロールにパーミッションを与えてください:
次に、同じく <literal>hibernate.cfg.xml</literal> でロールにパーミッションを与えてください:
</para>
<programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
<para>
このロール名は使用するJACCプロバイダに理解されるロールです。
このロール名は使用するJACCプロバイダに理解されるロールです。
</para>
</sect1>

View File

@ -1,22 +1,22 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="example-mappings">
<title>例:いろいろなマッピング</title>
<title>例:いろいろなマッピング</title>
<para>
この章では、より複雑な関連のマッピングをいくつか紹介します。
この章では、より複雑な関連のマッピングをいくつか紹介します。
</para>
<sect1 id="example-mappings-emp">
<title>雇用者/従業員</title>
<title>雇用者/従業員</title>
<para>
<literal>Employer</literal><literal>Employee</literal> の関係を表す以下のモデルは、
関連の表現に実際のエンティティクラス( <literal>Employment</literal>
を使います。
なぜなら、同じ2つのパーティに複数の期間雇用されるということがありえるからです。
お金の値と従業員の名前をモデル化するためにコンポーネントを使っています。
<literal>Employer</literal><literal>Employee</literal> の関係を表す以下のモデルは、
関連の表現に実際のエンティティクラス( <literal>Employment</literal>
を使います。
なぜなら、同じ2つのパーティに複数の期間雇用されるということがありえるからです。
お金の値と従業員の名前をモデル化するためにコンポーネントを使っています。
</para>
<mediaobject>
@ -29,7 +29,7 @@
</mediaobject>
<para>
マッピングドキュメントの一例です:
マッピングドキュメントの一例です:
</para>
<programlisting><![CDATA[<hibernate-mapping>
@ -82,7 +82,7 @@
</hibernate-mapping>]]></programlisting>
<para>
<literal>SchemaExport</literal> で生成したテーブルスキーマです。
<literal>SchemaExport</literal> で生成したテーブルスキーマです。
</para>
<programlisting><![CDATA[create table employers (
@ -122,14 +122,14 @@ create sequence employer_id_seq]]></programlisting>
</sect1>
<sect1 id="example-mappings-authorwork">
<title>作者/作品</title>
<title>作者/作品</title>
<para>
<literal>Work</literal> , <literal>Author</literal> そして <literal>Person</literal>
の関係を表す以下のモデルを考えてみてください。
<literal>Work</literal><literal>Author</literal> の関係を多対多関連で表しています。
<literal>Author</literal><literal>Person</literal> の関係は一対一関連として表しています。
他には <literal>Author</literal><literal>Person</literal> を拡張するという方法もあります。
<literal>Work</literal> , <literal>Author</literal> そして <literal>Person</literal>
の関係を表す以下のモデルを考えてみてください。
<literal>Work</literal><literal>Author</literal> の関係を多対多関連で表しています。
<literal>Author</literal><literal>Person</literal> の関係は一対一関連として表しています。
他には <literal>Author</literal><literal>Person</literal> を拡張するという方法もあります。
</para>
<mediaobject>
@ -142,7 +142,7 @@ create sequence employer_id_seq]]></programlisting>
</mediaobject>
<para>
以下のマッピングドキュメントはこのような関係を正確に表現しています。
以下のマッピングドキュメントはこのような関係を正確に表現しています。
</para>
<programlisting><![CDATA[<hibernate-mapping>
@ -198,11 +198,11 @@ create sequence employer_id_seq]]></programlisting>
</hibernate-mapping>]]></programlisting>
<para>
このマッピングには4つのテーブルがあります。
このマッピングには4つのテーブルがあります。
<literal>works</literal> , <literal>authors</literal> , <literal>persons</literal>
はそれぞれ、仕事、作者、人のデータを保持します。
<literal>author_work</literal> は作者と作品をリンクする関連テーブルです。
以下は <literal>SchemaExport</literal> で生成したテーブルスキーマです。
はそれぞれ、仕事、作者、人のデータを保持します。
<literal>author_work</literal> は作者と作品をリンクする関連テーブルです。
以下は <literal>SchemaExport</literal> で生成したテーブルスキーマです。
</para>
<programlisting><![CDATA[create table works (
@ -243,17 +243,17 @@ alter table author_work
</sect1>
<sect1 id="example-mappings-customerorderproduct">
<title>顧客/注文/製品</title>
<title>顧客/注文/製品</title>
<para>
さて、 <literal>Customer</literal> , <literal>Order</literal> , <literal>LineItem</literal>
<literal>Product</literal> の関係を表すモデルを考えてみましょう。
<literal>Customer</literal><literal>Order</literal> は一対多の関連ですが、
さて、 <literal>Customer</literal> , <literal>Order</literal> , <literal>LineItem</literal>
<literal>Product</literal> の関係を表すモデルを考えてみましょう。
<literal>Customer</literal><literal>Order</literal> は一対多の関連ですが、
<literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>
はどのように表現するべきでしょうか?
<literal>LineItem</literal> を、<literal>Order</literal><literal>Product</literal>
の多対多関連を表現する関連クラスとしてマッピングしました。
Hibernateではこれをコンポジット要素と呼びます。
はどのように表現するべきでしょうか?
<literal>LineItem</literal> を、<literal>Order</literal><literal>Product</literal>
の多対多関連を表現する関連クラスとしてマッピングしました。
Hibernateではこれをコンポジット要素と呼びます。
</para>
<mediaobject>
@ -266,7 +266,7 @@ alter table author_work
</mediaobject>
<para>
マッピングドキュメント:
マッピングドキュメント:
</para>
<programlisting><![CDATA[<hibernate-mapping>
@ -309,8 +309,8 @@ alter table author_work
<para>
<literal>customers</literal> , <literal>orders</literal> , <literal>line_items</literal> ,
<literal>products</literal> はそれぞれ、顧客、注文、注文明細、製品のデータを保持します。
<literal>line_items</literal> は注文と製品をリンクする関連テーブルとしても働きます。
<literal>products</literal> はそれぞれ、顧客、注文、注文明細、製品のデータを保持します。
<literal>line_items</literal> は注文と製品をリンクする関連テーブルとしても働きます。
</para>
<programlisting><![CDATA[create table customers (
@ -350,18 +350,18 @@ alter table line_items
</sect1>
<sect1 id="misc">
<title>種々雑多なマッピング例</title>
<title>種々雑多なマッピング例</title>
<para>
ここにある例はすべてHibernateのテストスイートから取りました。
そこには、他にもたくさんのマッピングの例があります。
Hibernateディストリビューションの <literal>test</literal> フォルダを見てください。
ここにある例はすべてHibernateのテストスイートから取りました。
そこには、他にもたくさんのマッピングの例があります。
Hibernateディストリビューションの <literal>test</literal> フォルダを見てください。
</para>
<para>TODO: ここに文章を埋める</para>
<para>TODO: ここに文章を埋める</para>
<sect2 id="example-mappings-typed-onetone">
<title>「型付けされた」一対一関連</title>
<title>「型付けされた」一対一関連</title>
<programlisting><![CDATA[<class name="Person">
<id name="name"/>
<one-to-one name="address"
@ -391,7 +391,7 @@ alter table line_items
</sect2>
<sect2 id="example-mappings-composite-key">
<title>複合キーの例</title>
<title>複合キーの例</title>
<programlisting><![CDATA[<class name="Customer">
<id name="customerId"
@ -508,7 +508,7 @@ alter table line_items
</sect2>
<sect2 id="example-mappings-composite-key-manytomany">
<title>複合キー属性を共有する多対多</title>
<title>複合キー属性を共有する多対多</title>
<programlisting><![CDATA[<class name="User" table="`User`">
<composite-id>
<key-property name="name"/>
@ -547,7 +547,7 @@ alter table line_items
</sect2>
<sect2 id="example-mappings-content-discrimination">
<title>discriminationに基づく内容</title>
<title>discriminationに基づく内容</title>
<programlisting><![CDATA[<class name="Person"
discriminator-value="P">
@ -601,7 +601,7 @@ alter table line_items
</sect2>
<sect2 id="example-mappings-association-alternatekeys" revision="2">
<title>代替キーの関連</title>
<title>代替キーの関連</title>
<programlisting><![CDATA[<class name="Person">
<id name="id">

View File

@ -1,70 +1,72 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="example-parentchild">
<title>例:親/子供
<title>例:親/子供
</title>
<para>
新規ユーザがHibernateを使ってまず最初に扱うモデルの一つに、親子型のモデル化があります。
このモデル化には二つのアプローチが存在します。とりわけ新規ユーザにとって、
さまざまな理由から最も便利だと思われるアプローチは、<literal></literal> から <literal>子供</literal>
への <literal>&lt;one-to-many&gt;</literal> 関連により <literal></literal><literal>子供</literal>
の両方をエンティティクラスとしてモデリングする方法です
(もう一つの方法は、<literal>子供</literal><literal>&lt;composite-element&gt;</literal> として定義するものです)。
これでHibernateにおける一対多関連のデフォルトのセマンティクスが、通常の複合要素のマッピングよりも、
親子関係のセマンティクスから遠いことがわかります。
それでは親子関係を効率的かつエレガントにモデリングするために、
<emphasis>カスケード操作を使った双方向一対多関連</emphasis> の扱い方を説明します。これはまったく難しいものではありません。
新規ユーザがHibernateを使ってまず最初に扱うモデルの一つに、親子型のモデル化があります。
このモデル化には二つのアプローチが存在します。とりわけ新規ユーザにとって、
さまざまな理由から最も便利だと思われるアプローチは、<literal></literal> から <literal>子供</literal>
への <literal>&lt;one-to-many&gt;</literal> 関連により <literal></literal><literal>子供</literal>
の両方をエンティティクラスとしてモデリングする方法です
(もう一つの方法は、<literal>子供</literal><literal>&lt;composite-element&gt;</literal> として定義するものです)。
これでHibernateにおける一対多関連のデフォルトのセマンティクスが、通常の複合要素のマッピングよりも、
親子関係のセマンティクスから遠いことがわかります。
それでは親子関係を効率的かつエレガントにモデリングするために、
<emphasis>カスケード操作を使った双方向一対多関連</emphasis> の扱い方を説明します。これはまったく難しいものではありません。
</para>
<sect1 id="example-parentchild-collections">
<title>コレクションに関する注意</title>
<title>コレクションに関する注意</title>
<para>
Hibernateのコレクションは自身のエンティティの論理的な部分と考えられ、
決して包含するエンティティのものではありません。これは致命的な違いです!
これは以下のような結果になります:
Hibernateのコレクションは自身のエンティティの論理的な部分と考えられ、
決して包含するエンティティのものではありません。これは致命的な違いです!
これは以下のような結果になります:
</para>
<itemizedlist>
<listitem>
<para>
オブジェクトをコレクションから削除、またはコレクションに追加するとき、
コレクションのオーナーのバージョン番号はインクリメントされます。
オブジェクトをコレクションから削除、またはコレクションに追加するとき、
コレクションのオーナーのバージョン番号はインクリメントされます。
</para>
</listitem>
<listitem>
<para>
もしコレクションから削除されたオブジェクトが値型のインスタンス
(例えばコンポジットエレメント)だったならば、そのオブジェクトは永続的ではなくなり、
その状態はデータベースから完全に削除されます。
同じように、値型のインスタンスをコレクションに追加すると、その状態はすぐに永続的になります。
もしコレクションから削除されたオブジェクトが値型のインスタンス
(例えばコンポジットエレメント)だったならば、そのオブジェクトは永続的ではなくなり、
その状態はデータベースから完全に削除されます。
同じように、値型のインスタンスをコレクションに追加すると、その状態はすぐに永続的になります。
</para>
</listitem>
<listitem>
<para>
一方、もしエンティティがコレクション(一対多または多対多関連)から削除されても、
デフォルトではそれは削除されません。この動作は完全に一貫しています。
すなわち、他のエンティティの内部状態を変更しても、関連するエンティティが消滅すべきではないということです。
同様に、エンティティがコレクションに追加されても、デフォルトではそのエンティティは永続的にはなりません。
一方、もしエンティティがコレクション(一対多または多対多関連)から削除されても、
デフォルトではそれは削除されません。この動作は完全に一貫しています。
すなわち、他のエンティティの内部状態を変更しても、関連するエンティティが消滅すべきではないということです。
同様に、エンティティがコレクションに追加されても、デフォルトではそのエンティティは永続的にはなりません。
</para>
</listitem>
</itemizedlist>
<para>
その代わりに、デフォルトの動作では、エンティティをコレクションに追加すると単に二つのエンティティ間のリンクを作成し、
一方エンティティを削除するとリンクも削除します。これはすべてのケースにおいて非常に適切です。
これが適切でないのは親/子関係の場合です。この場合子供の生存は親のライフサイクルに制限されるからです。
その代わりに、デフォルトの動作では、エンティティをコレクションに追加すると単に二つのエンティティ間のリンクを作成し、
一方エンティティを削除するとリンクも削除します。これはすべてのケースにおいて非常に適切です。
これが適切でないのは親/子関係の場合です。この場合子供の生存は親のライフサイクルに制限されるからです。
</para>
</sect1>
<sect1 id="example-parentchild-bidir">
<title>双方向一対多
<title>双方向一対多
</title>
<para>
<literal>Parent</literal> から <literal>Child</literal> への単純な <literal>&lt;one-to-many&gt;</literal> 関連から始めるとします。
<literal>Parent</literal> から <literal>Child</literal> への単純な <literal>&lt;one-to-many&gt;</literal> 関連から始めるとします。
</para>
<programlisting><![CDATA[<set name="children">
@ -73,7 +75,7 @@
</set>]]></programlisting>
<para>
以下のコードを実行すると、
以下のコードを実行すると、
</para>
<programlisting><![CDATA[Parent p = .....;
@ -83,25 +85,25 @@ session.save(c);
session.flush();]]></programlisting>
<para>
Hibernateは二つのSQL文を発行します:
Hibernateは二つのSQL文を発行します:
</para>
<itemizedlist>
<listitem>
<para>
<literal>c</literal>に対するレコードを生成する<literal>INSERT</literal>
<literal>c</literal>に対するレコードを生成する<literal>INSERT</literal>
</para>
</listitem>
<listitem>
<para>
<literal>p</literal>から<literal>c</literal>へのリンクを作成する<literal>UPDATE</literal>
<literal>p</literal>から<literal>c</literal>へのリンクを作成する<literal>UPDATE</literal>
</para>
</listitem>
</itemizedlist>
<para>
これは非効率的なだけではなく、<literal>parent_id</literal> カラムにおいて <literal>NOT NULL</literal> 制約に違反します。
コレクションのマッピングで <literal>not-null="true"</literal> と指定することで、null制約違反を解決することができます:
これは非効率的なだけではなく、<literal>parent_id</literal> カラムにおいて <literal>NOT NULL</literal> 制約に違反します。
コレクションのマッピングで <literal>not-null="true"</literal> と指定することで、null制約違反を解決することができます:
</para>
<programlisting><![CDATA[<set name="children">
@ -110,24 +112,24 @@ session.flush();]]></programlisting>
</set>]]></programlisting>
<para>
しかしこの解決策は推奨できません。
しかしこの解決策は推奨できません。
</para>
<para>
この動作の根本的な原因は、<literal>p</literal> から <literal>c</literal> へのリンク
(外部キー <literal>parent_id</literal>)は <literal>Child</literal> オブジェクトの状態の一部とは考えられず、
そのため <literal>INSERT</literal> によってリンクが生成されないことです。
ですから、解決策はリンクをChildマッピングの一部にすることです。
この動作の根本的な原因は、<literal>p</literal> から <literal>c</literal> へのリンク
(外部キー <literal>parent_id</literal>)は <literal>Child</literal> オブジェクトの状態の一部とは考えられず、
そのため <literal>INSERT</literal> によってリンクが生成されないことです。
ですから、解決策はリンクをChildマッピングの一部にすることです。
</para>
<programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
<para>
(また <literal>Child</literal> クラスに <literal>parent</literal> プロパティを追加する必要があります。)
(また <literal>Child</literal> クラスに <literal>parent</literal> プロパティを追加する必要があります。)
</para>
<para>
それでは <literal>Child</literal> エンティティがリンクの状態を制御するようになったので、
コレクションがリンクを更新しないようにしましょう。それには <literal>inverse</literal> 属性を使います。
それでは <literal>Child</literal> エンティティがリンクの状態を制御するようになったので、
コレクションがリンクを更新しないようにしましょう。それには <literal>inverse</literal> 属性を使います。
</para>
<programlisting><![CDATA[<set name="children" inverse="true">
@ -136,7 +138,7 @@ session.flush();]]></programlisting>
</set>]]></programlisting>
<para>
以下のコードを使えば、新しい <literal>Child</literal> を追加することができます。
以下のコードを使えば、新しい <literal>Child</literal> を追加することができます。
</para>
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
@ -147,11 +149,11 @@ session.save(c);
session.flush();]]></programlisting>
<para>
これにより、SQLの <literal>INSERT</literal> 文が一つだけが発行されるようになりました!
これにより、SQLの <literal>INSERT</literal> 文が一つだけが発行されるようになりました!
</para>
<para>
もう少し強化するには、<literal>Parent</literal><literal>addChild()</literal> メソッドを作成します。
もう少し強化するには、<literal>Parent</literal><literal>addChild()</literal> メソッドを作成します。
</para>
<programlisting><![CDATA[public void addChild(Child c) {
@ -160,7 +162,7 @@ session.flush();]]></programlisting>
}]]></programlisting>
<para>
<literal>Child</literal> を追加するコードはこのようになります。
<literal>Child</literal> を追加するコードはこのようになります。
</para>
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
@ -172,10 +174,10 @@ session.flush();]]></programlisting>
</sect1>
<sect1 id="example-parentchild-cascades">
<title>ライフサイクルのカスケード</title>
<title>ライフサイクルのカスケード</title>
<para>
明示的に <literal>save()</literal> をコールするのはまだ煩わしいものです。これをカスケードを使って対処します。
明示的に <literal>save()</literal> をコールするのはまだ煩わしいものです。これをカスケードを使って対処します。
</para>
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
@ -184,7 +186,7 @@ session.flush();]]></programlisting>
</set>]]></programlisting>
<para>
これにより先ほどのコードをこのように単純化します
これにより先ほどのコードをこのように単純化します
</para>
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
@ -193,8 +195,8 @@ p.addChild(c);
session.flush();]]></programlisting>
<para>
同様に <literal>Parent</literal> を保存または削除するときに、子供を一つ一つ取り出して扱う必要はありません。
以下のコードは <literal>p</literal> を削除し、そしてデータベースからその子供をすべて削除します。
同様に <literal>Parent</literal> を保存または削除するときに、子供を一つ一つ取り出して扱う必要はありません。
以下のコードは <literal>p</literal> を削除し、そしてデータベースからその子供をすべて削除します。
</para>
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
@ -202,7 +204,7 @@ session.delete(p);
session.flush();]]></programlisting>
<para>
しかしこのコードは
しかしこのコードは
</para>
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
@ -212,9 +214,9 @@ c.setParent(null);
session.flush();]]></programlisting>
<para>
データベースから <literal>c</literal> を削除しません。<literal>p</literal> へのリンクを削除する
(そしてこのケースでは <literal>NOT NULL</literal> 制約違反を引き起こす)だけです。
<literal>Child</literal><literal>delete()</literal> を明示する必要があります。
データベースから <literal>c</literal> を削除しません。<literal>p</literal> へのリンクを削除する
(そしてこのケースでは <literal>NOT NULL</literal> 制約違反を引き起こす)だけです。
<literal>Child</literal><literal>delete()</literal> を明示する必要があります。
</para>
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
@ -224,9 +226,9 @@ session.delete(c);
session.flush();]]></programlisting>
<para>
今このケースでは実際に <literal>Child</literal> が親なしでは存在できないようになりました。
そのため、もしコレクションから <literal>Child</literal> を取り除く場合、これも削除したいです。
そのためには <literal>cascade="all-delete-orphan"</literal> を使わなければなりません。
今このケースでは実際に <literal>Child</literal> が親なしでは存在できないようになりました。
そのため、もしコレクションから <literal>Child</literal> を取り除く場合、これも削除したいです。
そのためには <literal>cascade="all-delete-orphan"</literal> を使わなければなりません。
</para>
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
@ -235,35 +237,35 @@ session.flush();]]></programlisting>
</set>]]></programlisting>
<para>
注意:コレクションのマッピングで <literal>inverse="true"</literal> と指定しても、
コレクションの要素のイテレーションによって、依然カスケードが実行されます。
そのためもしカスケードでオブジェクトをセーブ、削除、更新する必要があるなら、
それをコレクションに追加しなければなりません。単に <literal>setParent()</literal> を呼ぶだけでは不十分です。
注意:コレクションのマッピングで <literal>inverse="true"</literal> と指定しても、
コレクションの要素のイテレーションによって、依然カスケードが実行されます。
そのためもしカスケードでオブジェクトをセーブ、削除、更新する必要があるなら、
それをコレクションに追加しなければなりません。単に <literal>setParent()</literal> を呼ぶだけでは不十分です。
</para>
</sect1>
<sect1 id="example-parentchild-update">
<title>カスケードと <literal>unsaved-value</literal></title>
<title>カスケードと <literal>unsaved-value</literal></title>
<para>
<literal>Parent</literal> が、ある <literal>Session</literal> でロードされ、UIのアクションで変更が加えられ、
<literal>update()</literal> を呼んでこの変更を新しいセッションで永続化したいとします。
<literal>Parent</literal> が子供のコレクションを持ち、カスケード更新が有効になっているため、
Hibernateはどの子供が新しくインスタンス化されたか、どれがデータベースの既存の行に相当するのかを知る必要があります。
<literal>Parent</literal><literal>Child</literal> の両方が <literal>java.lang.Long</literal>
型の識別プロパティを生成したとしましょう。
Hibernateはどの子供が新しいものかを決定するために識別プロパティの値を使います(versionやtimestampプロパティも使えます。
<xref linkend="manipulatingdata-updating-detached"/> 参照)。Hibernate3になって、
明示的に <literal>unsaved-value</literal> を指定する必要はなくなりました。
<literal>Parent</literal> が、ある <literal>Session</literal> でロードされ、UIのアクションで変更が加えられ、
<literal>update()</literal> を呼んでこの変更を新しいセッションで永続化したいとします。
<literal>Parent</literal> が子供のコレクションを持ち、カスケード更新が有効になっているため、
Hibernateはどの子供が新しくインスタンス化されたか、どれがデータベースの既存の行に相当するのかを知る必要があります。
<literal>Parent</literal><literal>Child</literal> の両方が <literal>java.lang.Long</literal>
型の識別プロパティを生成したとしましょう。
Hibernateはどの子供が新しいものかを決定するために識別プロパティの値を使います(versionやtimestampプロパティも使えます。
<xref linkend="manipulatingdata-updating-detached"/> 参照)。Hibernate3になって、
明示的に <literal>unsaved-value</literal> を指定する必要はなくなりました。
</para>
<para>
以下のコードは <literal>parent</literal><literal>child</literal> を更新し、<literal>newChild</literal> を挿入します。
以下のコードは <literal>parent</literal><literal>child</literal> を更新し、<literal>newChild</literal> を挿入します。
</para>
<programlisting><![CDATA[//parent and child were both loaded in a previous session
//parentとchildは両方とも、以前のSessionでロードされています
//parentとchildは両方とも、以前のSessionでロードされています
parent.addChild(child);
Child newChild = new Child();
parent.addChild(newChild);
@ -271,11 +273,11 @@ session.update(parent);
session.flush();]]></programlisting>
<para>
これらは生成された識別子の場合には非常に良いのですが、割り当てられた識別子と複合識別子の場合はどうでしょうか?
これはHibernateが、ユーザにより割り当てられた識別子を持つ新しくインスタンス化されたオブジェクトと、
以前のSessionでロードされたオブジェクトを区別できないため、より難しいです。
この場合、Hibernateはタイムスタンプかバージョンのプロパティのどちらかを使うか、二次キャッシュに問い合わせます。
最悪の場合、行が存在するかどうかデータベースを見ます。
これらは生成された識別子の場合には非常に良いのですが、割り当てられた識別子と複合識別子の場合はどうでしょうか?
これはHibernateが、ユーザにより割り当てられた識別子を持つ新しくインスタンス化されたオブジェクトと、
以前のSessionでロードされたオブジェクトを区別できないため、より難しいです。
この場合、Hibernateはタイムスタンプかバージョンのプロパティのどちらかを使うか、二次キャッシュに問い合わせます。
最悪の場合、行が存在するかどうかデータベースを見ます。
</para>
<!-- undocumenting
@ -341,22 +343,22 @@ public boolean onSave(Object entity,
</sect1>
<sect1 id="example-parentchild-conclusion">
<title>結論
<title>結論
</title>
<para>
ここではかなりの量を要約したので、最初の頃は混乱しているように思われるかもしれません。
しかし実際は、すべて非常に良く動作します。ほとんどのHibernateアプリケーションでは、多くの場面で親子パターンを使用します。
ここではかなりの量を要約したので、最初の頃は混乱しているように思われるかもしれません。
しかし実際は、すべて非常に良く動作します。ほとんどのHibernateアプリケーションでは、多くの場面で親子パターンを使用します。
</para>
<para>
最初の段落で代替方法について触れました。上記のような問題は <literal>&lt;composite-element&gt;</literal> マッピングの場合は存在せず、
にもかかわらずそれは確かに親子関係のセマンティクスを持ちます。
しかし残念ながら、複合要素クラスには二つの大きな制限があります:
1つは複合要素はコレクションを持つことができないことです。もうひとつは、
ユニークな親ではないエンティティの子供となるべきではないということです
最初の段落で代替方法について触れました。上記のような問題は <literal>&lt;composite-element&gt;</literal> マッピングの場合は存在せず、
にもかかわらずそれは確かに親子関係のセマンティクスを持ちます。
しかし残念ながら、複合要素クラスには二つの大きな制限があります:
1つは複合要素はコレクションを持つことができないことです。もうひとつは、
ユニークな親ではないエンティティの子供となるべきではないということです
</para>
</sect1>
</chapter>
</chapter>

View File

@ -1,15 +1,17 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="example-weblog">
<title>例: Weblogアプリケーション</title>
<title>例: Weblogアプリケーション</title>
<sect1 id="example-weblog-classes">
<title>永続クラス
<title>永続クラス
</title>
<para>
永続クラスがウェブログと、ウェブログに掲示された項目を表しています。
それらは通常の親子関係としてモデリングされますが、
setではなく順序を持ったbagを使用することにします。
永続クラスがウェブログと、ウェブログに掲示された項目を表しています。
それらは通常の親子関係としてモデリングされますが、
setではなく順序を持ったbagを使用することにします。
</para>
<programlisting><![CDATA[package eg;
@ -88,11 +90,11 @@ public class BlogItem {
</sect1>
<sect1 id="example-weblog-mappings">
<title>Hibernateのマッピング
<title>Hibernateのマッピング
</title>
<para>
XMLマッピングは、今ではとても簡単なはずです。
XMLマッピングは、今ではとても簡単なはずです。
</para>
<programlisting><![CDATA[<?xml version="1.0"?>
@ -182,11 +184,11 @@ public class BlogItem {
</sect1>
<sect1 id="example-weblog-code">
<title>Hibernateのコード</title>
<title>Hibernateのコード</title>
<para>
以下のクラスは、
Hibernateでこれらのクラスを使ってできることをいくつか示しています。
以下のクラスは、
Hibernateでこれらのクラスを使ってできることをいくつか示しています。
</para>
<programlisting><![CDATA[package eg;

View File

@ -1,32 +1,34 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="filters">
<title>データのフィルタリング</title>
<title>データのフィルタリング</title>
<para>
Hibernate3では「可視性」ルールに基づいてデータを扱うための画期的な方法を用意しています。
<emphasis>Hibernate filter</emphasis> はグローバルで、名前付きで、パラメータ化されたフィルタです。
これはHibernateセッションごとに有効無効を切り替えられます。
Hibernate3では「可視性」ルールに基づいてデータを扱うための画期的な方法を用意しています。
<emphasis>Hibernate filter</emphasis> はグローバルで、名前付きで、パラメータ化されたフィルタです。
これはHibernateセッションごとに有効無効を切り替えられます。
</para>
<sect1 id="objectstate-filters">
<title>Hibernateのフィルタ</title>
<title>Hibernateのフィルタ</title>
<para>
Hibernate3はフィルタクライテリアをあらかじめ定義し、
これらのフィルタをクラスやコレクションレベルに加える機能を加えました。
フィルタクライテリアは制約節を定義する機能です。
これらのフィルタ条件はパラメータ化できるということを除き、
クラスやさまざまなコレクション要素で利用可能な「where」句に非常によく似ています。
アプリケーションは、与えられたフィルタを可能にすべきか、
そしてそのパラメータ値を何にすべきかを実行時に決定することができます。
フィルタはデータベースビューのように使用されますが、アプリケーション内ではパラメータ化されます。
Hibernate3はフィルタクライテリアをあらかじめ定義し、
これらのフィルタをクラスやコレクションレベルに加える機能を加えました。
フィルタクライテリアは制約節を定義する機能です。
これらのフィルタ条件はパラメータ化できるということを除き、
クラスやさまざまなコレクション要素で利用可能な「where」句に非常によく似ています。
アプリケーションは、与えられたフィルタを可能にすべきか、
そしてそのパラメータ値を何にすべきかを実行時に決定することができます。
フィルタはデータベースビューのように使用されますが、アプリケーション内ではパラメータ化されます。
</para>
<para>
フィルタを使うためにはまず、適切なマッピング要素に定義、追加しなくてはなりません。
フィルタを定義するためには、
<literal>&lt;hibernate-mapping/&gt;</literal> 要素内で <literal>&lt;filter-def/&gt;</literal> 要素を使用します。:
フィルタを使うためにはまず、適切なマッピング要素に定義、追加しなくてはなりません。
フィルタを定義するためには、
<literal>&lt;hibernate-mapping/&gt;</literal> 要素内で <literal>&lt;filter-def/&gt;</literal> 要素を使用します。:
</para>
<programlisting><![CDATA[<filter-def name="myFilter">
@ -34,7 +36,7 @@
</filter-def>]]></programlisting>
<para>
そうしてフィルタはクラスへと結び付けられます。:
そうしてフィルタはクラスへと結び付けられます。:
</para>
<programlisting><![CDATA[<class name="myClass" ...>
@ -43,7 +45,7 @@
</class>]]></programlisting>
<para>
また、コレクションに対しては次のようになります。:
また、コレクションに対しては次のようになります。:
</para>
<programlisting><![CDATA[<set ...>
@ -51,27 +53,27 @@
</set>]]></programlisting>
<para>
どちらに対しても(また、それぞれを複数)同時に設定することもできます。
どちらに対しても(また、それぞれを複数)同時に設定することもできます。
</para>
<para>
<literal>Session</literal> 上のメソッドは <literal>enableFilter(String filterName)</literal>,
<literal>getEnabledFilter(String filterName)</literal>, <literal>disableFilter(String filterName)</literal> です。
デフォルトでは、フィルタは与えられたセッションに対して使用 <emphasis>できません</emphasis>
<literal>Filter</literal> インスタンスを返り値とする <literal>Session.enabledFilter()</literal> メソッドを使うことで、
フィルタは明示的に使用可能となります。
上で定義した単純なフィルタの使用は、このようになります。:
<literal>Session</literal> 上のメソッドは <literal>enableFilter(String filterName)</literal>,
<literal>getEnabledFilter(String filterName)</literal>, <literal>disableFilter(String filterName)</literal> です。
デフォルトでは、フィルタは与えられたセッションに対して使用 <emphasis>できません</emphasis>
<literal>Filter</literal> インスタンスを返り値とする <literal>Session.enabledFilter()</literal> メソッドを使うことで、
フィルタは明示的に使用可能となります。
上で定義した単純なフィルタの使用は、このようになります。:
</para>
<programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
<para>
org.hibernate.Filterインターフェイスのメソッドは、
Hibernateの多くに共通しているメソッド連鎖を許していることに注意してください。
org.hibernate.Filterインターフェイスのメソッドは、
Hibernateの多くに共通しているメソッド連鎖を許していることに注意してください。
</para>
<para>
有効なレコードデータパターンを持つ一時データを使った完全な例です:
有効なレコードデータパターンを持つ一時データを使った完全な例です:
</para>
<programlisting><![CDATA[<filter-def name="effectiveDate">
@ -105,8 +107,8 @@
</class>]]></programlisting>
<para>
常に現在の有効レコードを返却することを保証するために、
単純に、社員データの検索より前にセッション上のフィルタを有効にします。
常に現在の有効レコードを返却することを保証するために、
単純に、社員データの検索より前にセッション上のフィルタを有効にします。
</para>
@ -119,16 +121,16 @@ List results = session.createQuery("from Employee as e where e.salary > :targetS
]]></programlisting>
<para>
上記のHQLでは、結果の給料の制約について明示的に触れただけですが、
有効になっているフィルタのおかげで、このクエリは給料が100万ドル以上の現役の社員だけを返します。
上記のHQLでは、結果の給料の制約について明示的に触れただけですが、
有効になっているフィルタのおかげで、このクエリは給料が100万ドル以上の現役の社員だけを返します。
</para>
<para>
(HQLかロードフェッチで外部結合を持つフィルタを使うつもりなら、
条件式の方向に注意してください。
(HQLかロードフェッチで外部結合を持つフィルタを使うつもりなら、
条件式の方向に注意してください。
これは左外部結合のために設定するのが最も安全です。
一般的に、演算子の後カラム名に続けて最初のパラメータを配置してください。
これは左外部結合のために設定するのが最も安全です。
一般的に、演算子の後カラム名に続けて最初のパラメータを配置してください。
</para>
</sect1>

View File

@ -1,67 +1,69 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="inheritance">
<title>継承マッピング</title>
<title>継承マッピング</title>
<sect1 id="inheritance-strategies" revision="3">
<title>3つの戦略</title>
<title>3つの戦略</title>
<para>
Hibernateは3つの基本的な継承のマッピング戦略をサポートします。
Hibernateは3つの基本的な継承のマッピング戦略をサポートします。
</para>
<itemizedlist>
<listitem>
<para>
クラス階層ごとのテーブルtable-per-class-hierarchy
クラス階層ごとのテーブルtable-per-class-hierarchy
</para>
</listitem>
<listitem>
<para>
サブクラスごとのテーブルtable-per-subclass
サブクラスごとのテーブルtable-per-subclass
</para>
</listitem>
<listitem>
<para>
具象クラスごとのテーブルtable-per-concrete-class
具象クラスごとのテーブルtable-per-concrete-class
</para>
</listitem>
</itemizedlist>
<para>
加えて4つ目に、Hibernateはわずかに異なる性質を持ったポリモーフィズムをサポートします。
加えて4つ目に、Hibernateはわずかに異なる性質を持ったポリモーフィズムをサポートします。
</para>
<itemizedlist>
<listitem>
<para>
暗黙的ポリモーフィズム
暗黙的ポリモーフィズム
</para>
</listitem>
</itemizedlist>
<para>
同一の継承階層の異なるブランチに対して異なるマッピング戦略を使うことができます。
その場合には全体の階層に渡るポリモーフィズムを実現するために暗黙的ポリモーフィズムを使用します。
しかし、Hibernateは同じルート <literal>&lt;class&gt;</literal> 要素内で
<literal>&lt;subclass&gt;</literal> マッピング、<literal>&lt;joined-subclass&gt;</literal> マッピング、
<literal>&lt;union-subclass&gt;</literal> マッピングの同時使用をサポートしていません。
<literal>&lt;subclass&gt;</literal> 要素と <literal>&lt;join&gt;</literal> 要素を組み合わせることで、
同一 <literal>&lt;class&gt;</literal> 要素内での table-per-hierarchy 戦略と
table-per-subclass 戦略の同時使用は可能です。次の例を見てください。
同一の継承階層の異なるブランチに対して異なるマッピング戦略を使うことができます。
その場合には全体の階層に渡るポリモーフィズムを実現するために暗黙的ポリモーフィズムを使用します。
しかし、Hibernateは同じルート <literal>&lt;class&gt;</literal> 要素内で
<literal>&lt;subclass&gt;</literal> マッピング、<literal>&lt;joined-subclass&gt;</literal> マッピング、
<literal>&lt;union-subclass&gt;</literal> マッピングの同時使用をサポートしていません。
<literal>&lt;subclass&gt;</literal> 要素と <literal>&lt;join&gt;</literal> 要素を組み合わせることで、
同一 <literal>&lt;class&gt;</literal> 要素内での table-per-hierarchy 戦略と
table-per-subclass 戦略の同時使用は可能です。次の例を見てください。
</para>
<para>
<literal>subclass</literal>, <literal>union-subclass</literal>
<literal>joined-subclass</literal> マッピングを複数のマッピングドキュメントに定義することが出来、
<literal>hibernate-mapping</literal> の直下に配置します。
これは新しいマッピングファイルを追加するだけで、クラス階層を拡張できるということです。
あらかじめマップしたスーパークラスを指定して、サブクラスマッピングに <literal>extends</literal>
属性を記述しなければなりません。
注意:この特徴により、以前はマッピング・ドキュメントの順番が重要でした。
Hibernate3からは、extendsキーワードを使う場合、マッピングドキュメントの順番は問題になりません。
<literal>subclass</literal>, <literal>union-subclass</literal>
<literal>joined-subclass</literal> マッピングを複数のマッピングドキュメントに定義することが出来、
<literal>hibernate-mapping</literal> の直下に配置します。
これは新しいマッピングファイルを追加するだけで、クラス階層を拡張できるということです。
あらかじめマップしたスーパークラスを指定して、サブクラスマッピングに <literal>extends</literal>
属性を記述しなければなりません。
注意:この特徴により、以前はマッピング・ドキュメントの順番が重要でした。
Hibernate3からは、extendsキーワードを使う場合、マッピングドキュメントの順番は問題になりません。
1つのマッピングファイル内で順番付けを行うときは、
依然として、サブクラスを定義する前にスーパークラスを定義する必要があります。)
1つのマッピングファイル内で順番付けを行うときは、
依然として、サブクラスを定義する前にスーパークラスを定義する必要があります。)
</para>
<programlisting><![CDATA[
@ -73,13 +75,13 @@
<sect2 id="inheritance-tableperclass" >
<title>クラス階層ごとのテーブルtable-per-class-hierarchy</title>
<title>クラス階層ごとのテーブルtable-per-class-hierarchy</title>
<para>
例えば、インターフェイス <literal>Payment</literal> と、それを実装した
<literal>CreditCardPayment</literal><literal>CashPayment</literal>
<literal>ChequePayment</literal> があるとします。階層ごとのテーブルマッピングは
以下のようになります。
例えば、インターフェイス <literal>Payment</literal> と、それを実装した
<literal>CreditCardPayment</literal><literal>CashPayment</literal>
<literal>ChequePayment</literal> があるとします。階層ごとのテーブルマッピングは
以下のようになります。
</para>
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
@ -102,19 +104,19 @@
</class>]]></programlisting>
<para>
ちょうど一つのテーブルが必要です。
このマッピング戦略には一つ大きな制限があります。
<literal>CCTYPE</literal> のような、サブクラスで宣言されたカラムは <literal>NOT NULL</literal>
制約を持てません。
ちょうど一つのテーブルが必要です。
このマッピング戦略には一つ大きな制限があります。
<literal>CCTYPE</literal> のような、サブクラスで宣言されたカラムは <literal>NOT NULL</literal>
制約を持てません。
</para>
</sect2>
<sect2 id="inheritance-tablepersubclass">
<title>サブクラスごとのテーブルtable-per-subclass</title>
<title>サブクラスごとのテーブルtable-per-subclass</title>
<para>
table-per-subclass マッピングは以下のようになります。
table-per-subclass マッピングは以下のようになります。
</para>
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
@ -139,24 +141,24 @@
</class>]]></programlisting>
<para>
このマッピングには4つのテーブルが必要です。3つのサブクラステーブルは
スーパークラステーブルとの関連を示す主キーを持っています
(実際、関係モデル上は一対一関連です)。
このマッピングには4つのテーブルが必要です。3つのサブクラステーブルは
スーパークラステーブルとの関連を示す主キーを持っています
(実際、関係モデル上は一対一関連です)。
</para>
</sect2>
<sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
<title>弁別子を用いた table-per-subclass</title>
<title>弁別子を用いた table-per-subclass</title>
<para>
Hibernateの table-per-subclass 実装は、discriminatorカラムを必要としないことを覚えておいてください。
Hibernate以外のO/Rマッパーは、table-per-subclass に異なる実装を用います。
それは、スーパークラスのテーブルにタイプdiscriminatorカラムを必要とします。
このアプローチは実装が困難になりますが、関係の視点から見ると、より正確なものです。
table-per-subclass 戦略でdiscriminatorカラムを使いたければ、
<literal>&lt;subclass&gt;</literal><literal>&lt;join&gt;</literal>
を以下のように組み合わせて使ってください。
Hibernateの table-per-subclass 実装は、discriminatorカラムを必要としないことを覚えておいてください。
Hibernate以外のO/Rマッパーは、table-per-subclass に異なる実装を用います。
それは、スーパークラスのテーブルにタイプdiscriminatorカラムを必要とします。
このアプローチは実装が困難になりますが、関係の視点から見ると、より正確なものです。
table-per-subclass 戦略でdiscriminatorカラムを使いたければ、
<literal>&lt;subclass&gt;</literal><literal>&lt;join&gt;</literal>
を以下のように組み合わせて使ってください。
</para>
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
@ -188,19 +190,19 @@
</class>]]></programlisting>
<para>
オプションの <literal>fetch="select"</literal> 宣言は、
スーパークラスのクエリ実行時に外部結合を使って、
サブクラスの <literal>ChequePayment</literal> データを取得しないように指定するためのものです。
オプションの <literal>fetch="select"</literal> 宣言は、
スーパークラスのクエリ実行時に外部結合を使って、
サブクラスの <literal>ChequePayment</literal> データを取得しないように指定するためのものです。
</para>
</sect2>
<sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
<title>table-per-subclass と table-per-class-hierarchy の混合</title>
<title>table-per-subclass と table-per-class-hierarchy の混合</title>
<para>
このアプローチを使用すると、table-per-hierarchy と table-per-subclass 戦略を
組み合わせる事も可能です。
このアプローチを使用すると、table-per-hierarchy と table-per-subclass 戦略を
組み合わせる事も可能です。
</para>
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
@ -225,8 +227,8 @@
</class>]]></programlisting>
<para>
いずれのマッピング戦略であっても、ルートである <literal>Payment</literal> クラスへの
ポリモーフィックな関連は <literal>&lt;many-to-one&gt;</literal> を使ってマッピングします。
いずれのマッピング戦略であっても、ルートである <literal>Payment</literal> クラスへの
ポリモーフィックな関連は <literal>&lt;many-to-one&gt;</literal> を使ってマッピングします。
</para>
<programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
@ -234,11 +236,11 @@
</sect2>
<sect2 id="inheritance-tableperconcrete" revision="2">
<title>具象クラスごとのテーブルtable-per-concrete-class</title>
<title>具象クラスごとのテーブルtable-per-concrete-class</title>
<para>
table-per-concrete-class 戦略のマッピングに対するアプローチは、2つあります。
1つ目は <literal>&lt;union-subclass&gt;</literal> を利用する方法です。
table-per-concrete-class 戦略のマッピングに対するアプローチは、2つあります。
1つ目は <literal>&lt;union-subclass&gt;</literal> を利用する方法です。
</para>
<programlisting><![CDATA[<class name="Payment">
@ -260,32 +262,32 @@
</class>]]></programlisting>
<para>
サブクラスごとに3つのテーブルが必要です。それぞれのテーブルは、継承プロパティを含んだ、
クラスの全てのプロパティに対するカラムを定義します。
サブクラスごとに3つのテーブルが必要です。それぞれのテーブルは、継承プロパティを含んだ、
クラスの全てのプロパティに対するカラムを定義します。
</para>
<para>
このアプローチには制限があります。
それは、プロパティがスーパークラスにマッピングされていた場合、
全てのサブクラスにおいてカラム名が同じでなければならないというものです。
Hibernateの今後のリリースで緩和されるかもしれません
&lt;union-subclass&gt; を使った table-per-concrete-class 戦略では識別子生成戦略を使用できません。
主キーを生成するためのシードは、全ての union subclass の階層内で共有する必要があるからです。
このアプローチには制限があります。
それは、プロパティがスーパークラスにマッピングされていた場合、
全てのサブクラスにおいてカラム名が同じでなければならないというものです。
Hibernateの今後のリリースで緩和されるかもしれません
&lt;union-subclass&gt; を使った table-per-concrete-class 戦略では識別子生成戦略を使用できません。
主キーを生成するためのシードは、全ての union subclass の階層内で共有する必要があるからです。
</para>
<para>
もしスーパークラスが抽象クラスなら、<literal>abstract="true"</literal>とマッピングします。
もちろん、スーパークラスが抽象クラスでないなら、スーパークラスのインスタンスを
保持するためのテーブルの追加が必要となります(上の例でのデフォルトは <literal>PAYMENT</literal> )。
もしスーパークラスが抽象クラスなら、<literal>abstract="true"</literal>とマッピングします。
もちろん、スーパークラスが抽象クラスでないなら、スーパークラスのインスタンスを
保持するためのテーブルの追加が必要となります(上の例でのデフォルトは <literal>PAYMENT</literal> )。
</para>
</sect2>
<sect2 id="inheritance-tableperconcreate-polymorphism">
<title>暗黙的ポリモーフィズムを用いた table-per-concrete-class</title>
<title>暗黙的ポリモーフィズムを用いた table-per-concrete-class</title>
<para>
もう一つのアプローチは暗黙的ポリモーフィズムの使用です。
もう一つのアプローチは暗黙的ポリモーフィズムの使用です。
</para>
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
@ -313,21 +315,21 @@
</class>]]></programlisting>
<para>
<literal>Payment</literal> インターフェイスがどこにも明示的に示されていないことに注意してください。
そして、<literal>Payment</literal> プロパティがそれぞれのサブクラスにマッピングされていることにも注意してください。
もし重複を避けたいのであれば、XMLエンティティの利用を考えてください。
(例: <literal>DOCTYPE</literal> 宣言における <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>
と、マッピングにおける <literal>&amp;allproperties;</literal>
<literal>Payment</literal> インターフェイスがどこにも明示的に示されていないことに注意してください。
そして、<literal>Payment</literal> プロパティがそれぞれのサブクラスにマッピングされていることにも注意してください。
もし重複を避けたいのであれば、XMLエンティティの利用を考えてください。
(例: <literal>DOCTYPE</literal> 宣言における <literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</literal>
と、マッピングにおける <literal>&amp;allproperties;</literal>
</para>
<para>
このアプローチの欠点は、Hibernateがポリモーフィックなクエリの実行時にSQL <literal>UNION</literal>
を生成しない点です。
このアプローチの欠点は、Hibernateがポリモーフィックなクエリの実行時にSQL <literal>UNION</literal>
を生成しない点です。
</para>
<para>
このマッピング戦略に対しては、<literal>Payment</literal> へのポリモーフィックな関連は
通常、<literal>&lt;any&gt;</literal> を使ってマッピングされます。
このマッピング戦略に対しては、<literal>Payment</literal> へのポリモーフィックな関連は
通常、<literal>&lt;any&gt;</literal> を使ってマッピングされます。
</para>
<programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
@ -341,15 +343,15 @@
</sect2>
<sect2 id="inheritace-mixingpolymorphism">
<title>他の継承マッピングと暗黙的ポリモーフィズムの組み合わせ</title>
<title>他の継承マッピングと暗黙的ポリモーフィズムの組み合わせ</title>
<para>
このマッピングについての更なる注意点があります。
サブクラスが自身を <literal>&lt;class&gt;</literal> 要素としてマッピングしているので、
(かつ <literal>Payment</literal> は単なるインターフェイスなので)、
それぞれのサブクラスは簡単にその他の継承階層の一部となります。
(しかも、今までどおり <literal>Payment</literal> インターフェイスに対するポリモーフィックなクエリ
を使用することができます)
このマッピングについての更なる注意点があります。
サブクラスが自身を <literal>&lt;class&gt;</literal> 要素としてマッピングしているので、
(かつ <literal>Payment</literal> は単なるインターフェイスなので)、
それぞれのサブクラスは簡単にその他の継承階層の一部となります。
(しかも、今までどおり <literal>Payment</literal> インターフェイスに対するポリモーフィックなクエリ
を使用することができます)
</para>
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
@ -381,14 +383,14 @@
</class>]]></programlisting>
<para>
もう一度述べますが、<literal>Payment</literal> は明示的に定義されません。
もし、<literal>Payment</literal> インターフェイスに対してクエリを実行するなら
(例えば <literal>from Payment</literal> 節を使って)、
Hibernateは自動的に <literal>CreditCardPayment</literal>
とCreditCardPaymentのサブクラス、<literal>Payment</literal> の実装であるため)、
および、<literal>CashPayment</literal><literal>ChequePayment</literal>
のインスタンスを返します。
<literal>NonelectronicTransaction</literal> インスタンスは返しません。
もう一度述べますが、<literal>Payment</literal> は明示的に定義されません。
もし、<literal>Payment</literal> インターフェイスに対してクエリを実行するなら
(例えば <literal>from Payment</literal> 節を使って)、
Hibernateは自動的に <literal>CreditCardPayment</literal>
とCreditCardPaymentのサブクラス、<literal>Payment</literal> の実装であるため)、
および、<literal>CashPayment</literal><literal>ChequePayment</literal>
のインスタンスを返します。
<literal>NonelectronicTransaction</literal> インスタンスは返しません。
</para>
</sect2>
@ -396,21 +398,21 @@
</sect1>
<sect1 id="inheritance-limitations">
<title>制限</title>
<title>制限</title>
<para>
table-per-concrete-class マッピング戦略への「暗黙的ポリモーフィズム」アプローチには
いくつかの制限があります。<literal>&lt;union-subclass&gt;</literal> マッピングに対しても
少し弱めの制限があります。
table-per-concrete-class マッピング戦略への「暗黙的ポリモーフィズム」アプローチには
いくつかの制限があります。<literal>&lt;union-subclass&gt;</literal> マッピングに対しても
少し弱めの制限があります。
</para>
<para>
次のテーブルに、Hibernateにおけるtable-per-concrete-classマッピングの
制限や暗黙的ポリモーフィズムの制限を示します。
次のテーブルに、Hibernateにおけるtable-per-concrete-classマッピングの
制限や暗黙的ポリモーフィズムの制限を示します。
</para>
<table frame="topbot">
<title>継承マッピングの機能</title>
<title>継承マッピングの機能</title>
<tgroup cols='8' align='left' colsep='1' rowsep='1'>
<colspec colname='c1' colwidth="1*"/>
<colspec colname='c2' colwidth="1*"/>
@ -422,15 +424,15 @@
<colspec colname='c8' colwidth="1*"/>
<thead>
<row>
<entry>継承戦略</entry>
<entry>多対一のポリモーフィズム</entry>
<entry>一対一のポリモーフィズム</entry>
<entry>一対多のポリモーフィズム</entry>
<entry>多対多のポリモーフィズム</entry>
<entry>ポリモーフィズムを使った<literal>load()/get()</literal></entry>
<entry>ポリモーフィズムを使ったクエリ</entry>
<entry>ポリモーフィズムを使った結合</entry>
<entry>外部結合によるフェッチ</entry>
<entry>継承戦略</entry>
<entry>多対一のポリモーフィズム</entry>
<entry>一対一のポリモーフィズム</entry>
<entry>一対多のポリモーフィズム</entry>
<entry>多対多のポリモーフィズム</entry>
<entry>ポリモーフィズムを使った<literal>load()/get()</literal></entry>
<entry>ポリモーフィズムを使ったクエリ</entry>
<entry>ポリモーフィズムを使った結合</entry>
<entry>外部結合によるフェッチ</entry>
</row>
</thead>
<tbody>
@ -443,7 +445,7 @@
<entry><literal>s.get(Payment.class, id)</literal></entry>
<entry><literal>from Payment p</literal></entry>
<entry><literal>from Order o join o.payment p</literal></entry>
<entry><emphasis>サポート</emphasis></entry>
<entry><emphasis>サポート</emphasis></entry>
</row>
<row>
<entry>table per subclass</entry>
@ -454,7 +456,7 @@
<entry><literal>s.get(Payment.class, id)</literal></entry>
<entry><literal>from Payment p</literal></entry>
<entry><literal>from Order o join o.payment p</literal></entry>
<entry><emphasis>サポート</emphasis></entry>
<entry><emphasis>サポート</emphasis></entry>
</row>
<row>
<entry>table per concrete-class (union-subclass)</entry>
@ -465,18 +467,18 @@
<entry><literal>s.get(Payment.class, id)</literal></entry>
<entry><literal>from Payment p</literal></entry>
<entry><literal>from Order o join o.payment p</literal></entry>
<entry><emphasis>サポート</emphasis></entry>
<entry><emphasis>サポート</emphasis></entry>
</row>
<row>
<entry>table per concrete class (implicit polymorphism)</entry>
<entry><literal>&lt;any&gt;</literal></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
<entry><literal>&lt;many-to-any&gt;</literal></entry>
<entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
<entry><literal>from Payment p</literal></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
<entry><emphasis>サポートしていません</emphasis></entry>
</row>
</tbody>
</tgroup>

View File

@ -1,28 +1,30 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="persistent-classes" revision="2">
<title>永続クラス</title>
<title>永続クラス</title>
<para>
永続クラスはビジネス上の問題のエンティティ例えば、Eコマースアプリケーションの顧客や注文
を実装するアプリケーションのクラスです。
永続クラスのすべてのインスタンスが永続状態であると見なされるわけではありません。
インスタンスは逆に一時的transientであったり、分離状態detachedであったりするかもしれません。
永続クラスはビジネス上の問題のエンティティ例えば、Eコマースアプリケーションの顧客や注文
を実装するアプリケーションのクラスです。
永続クラスのすべてのインスタンスが永続状態であると見なされるわけではありません。
インスタンスは逆に一時的transientであったり、分離状態detachedであったりするかもしれません。
</para>
<para>
Plain Old Java Object (POJO)プログラミングモデルとしても知られる
いくつかの単純なルールに従うなら、Hibernateは最もよく働きます。
しかしこれらのルールは難しいものではありません。
実際Hibernate3は永続オブジェクトの性質にほとんど何の前提も置いていません。
ドメインモデルは他の方法で表現することもできます。
例えば <literal>Map</literal> インスタンスのツリーを使う方法があります。
Plain Old Java Object (POJO)プログラミングモデルとしても知られる
いくつかの単純なルールに従うなら、Hibernateは最もよく働きます。
しかしこれらのルールは難しいものではありません。
実際Hibernate3は永続オブジェクトの性質にほとんど何の前提も置いていません。
ドメインモデルは他の方法で表現することもできます。
例えば <literal>Map</literal> インスタンスのツリーを使う方法があります。
</para>
<sect1 id="persistent-classes-pojo">
<title>単純なPOJOの例</title>
<title>単純なPOJOの例</title>
<para>
ほとんどのJavaアプリケーションにはネコ科の動物を表現する永続クラスが必要です。
ほとんどのJavaアプリケーションにはネコ科の動物を表現する永続クラスが必要です。
</para>
<programlisting><![CDATA[package eg;
@ -105,51 +107,51 @@ public class Cat {
}]]></programlisting>
<para>
従うべき4つのルールがあります
従うべき4つのルールがあります
</para>
<sect2 id="persistent-classes-pojo-constructor" revision="1">
<title>引数のないコンストラクタを実装する</title>
<title>引数のないコンストラクタを実装する</title>
<para>
<literal>Cat</literal> には引数のないコンストラクタがあります。
Hibernateが <literal>Constructor.newInstance()</literal> を使って永続クラスの
インスタンス化を行えるように、すべての永続クラスにはデフォルトコンストラクタ
publicでなくても構いませんがなければなりません。
Hibernateの実行時プロキシ生成のために、少なくとも <emphasis>package</emphasis>
の可視性を持つデフォルトコンストラクタを強くお勧めします。
<literal>Cat</literal> には引数のないコンストラクタがあります。
Hibernateが <literal>Constructor.newInstance()</literal> を使って永続クラスの
インスタンス化を行えるように、すべての永続クラスにはデフォルトコンストラクタ
publicでなくても構いませんがなければなりません。
Hibernateの実行時プロキシ生成のために、少なくとも <emphasis>package</emphasis>
の可視性を持つデフォルトコンストラクタを強くお勧めします。
</para>
</sect2>
<sect2 id="persistent-classes-pojo-identifier" revision="2">
<title>識別子プロパティを用意する(オプション)</title>
<title>識別子プロパティを用意する(オプション)</title>
<para>
<literal>Cat</literal> には <literal>id</literal> というプロパティがあります。
このプロパティはデータベーステーブルの主キーカラムへマッピングされます。
このプロパティの名前は何でも構いませんし、型はどのようなプリミティブ型でも、
プリミティブの「ラッパー」型でも、<literal>java.lang.String</literal>
<literal>java.util.Date</literal> でも構いません。
(もしレガシーデータベーステーブルが複合キーを持つならば、
今述べたような型のプロパティを持つユーザ定義のクラスを使うことさえ可能です。
後で複合識別子の節を見てください。)
<literal>Cat</literal> には <literal>id</literal> というプロパティがあります。
このプロパティはデータベーステーブルの主キーカラムへマッピングされます。
このプロパティの名前は何でも構いませんし、型はどのようなプリミティブ型でも、
プリミティブの「ラッパー」型でも、<literal>java.lang.String</literal>
<literal>java.util.Date</literal> でも構いません。
(もしレガシーデータベーステーブルが複合キーを持つならば、
今述べたような型のプロパティを持つユーザ定義のクラスを使うことさえ可能です。
後で複合識別子の節を見てください。)
</para>
<para>
識別子プロパティは厳密にはオプションです。
これを省略して、Hibernateに内部的にオブジェクトの識別子を追跡させることは可能です。
しかしおすすめはしません。
識別子プロパティは厳密にはオプションです。
これを省略して、Hibernateに内部的にオブジェクトの識別子を追跡させることは可能です。
しかしおすすめはしません。
</para>
<para>
実際に、識別子プロパティを宣言するクラスだけが利用可能な機能がいくつかあります:
実際に、識別子プロパティを宣言するクラスだけが利用可能な機能がいくつかあります:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
分離オブジェクトの連鎖的な再追加(カスケード更新やカスケードマージ)。
<xref linkend="objectstate-transitive"/> を参照してください。
分離オブジェクトの連鎖的な再追加(カスケード更新やカスケードマージ)。
<xref linkend="objectstate-transitive"/> を参照してください。
</para>
</listitem>
<listitem>
@ -165,47 +167,47 @@ public class Cat {
</itemizedlist>
<para>
永続クラスには、一貫した名前の識別子プロパティを定義することをお勧めします。
さらにnull値を取れる(つまりプリミティブではない)型を使った方がよいでしょう。
永続クラスには、一貫した名前の識別子プロパティを定義することをお勧めします。
さらにnull値を取れる(つまりプリミティブではない)型を使った方がよいでしょう。
</para>
</sect2>
<sect2 id="persistent-classes-pojo-final">
<title>finalクラスにしないオプション</title>
<title>finalクラスにしないオプション</title>
<para>
Hibernateの中心的な特徴である <emphasis>プロキシ</emphasis> は、
永続クラスがfinalでないこと、またはメソッドを全部publicで宣言している
インターフェイスが実装されているかに依存しています。
Hibernateの中心的な特徴である <emphasis>プロキシ</emphasis> は、
永続クラスがfinalでないこと、またはメソッドを全部publicで宣言している
インターフェイスが実装されているかに依存しています。
</para>
<para>
Hibernateでインターフェイスを実装していない <literal>final</literal> クラスを永続化することはできますが、
遅延関連フェッチに対してプロキシを使うことはできなくなります。
これはパフォーマンスチューニングへの選択肢を狭めることになります。
Hibernateでインターフェイスを実装していない <literal>final</literal> クラスを永続化することはできますが、
遅延関連フェッチに対してプロキシを使うことはできなくなります。
これはパフォーマンスチューニングへの選択肢を狭めることになります。
</para>
<para>
finalではないクラスで <literal>public final</literal> メソッドを定義することも避けるべきです。
<literal>public final</literal> メソッドを持つクラスを使いたければ、
<literal>lazy="false"</literal> と設定して明示的にプロキシを無効にしなければなりません。
finalではないクラスで <literal>public final</literal> メソッドを定義することも避けるべきです。
<literal>public final</literal> メソッドを持つクラスを使いたければ、
<literal>lazy="false"</literal> と設定して明示的にプロキシを無効にしなければなりません。
</para>
</sect2>
<sect2 id="persistent-classes-pojo-accessors" revision="2">
<title>永続フィールドに対するアクセサとミューテータを定義する(オプション)</title>
<title>永続フィールドに対するアクセサとミューテータを定義する(オプション)</title>
<para>
<literal>Cat</literal> ではすべての永続フィールドに対してアクセサメソッドを定義しています。
他の多くのORMツールは、永続インスタンス変数を直接永続化します。
私たちはリレーショナルスキーマとクラスの内部構造を分離する方が良いと信じています。
デフォルトでは、HibernateはJavaBeanスタイルのプロパティを永続化し、
<literal>Cat</literal> ではすべての永続フィールドに対してアクセサメソッドを定義しています。
他の多くのORMツールは、永続インスタンス変数を直接永続化します。
私たちはリレーショナルスキーマとクラスの内部構造を分離する方が良いと信じています。
デフォルトでは、HibernateはJavaBeanスタイルのプロパティを永続化し、
<literal>getFoo</literal>, <literal>isFoo</literal>, <literal>setFoo</literal>
形式のメソッド名を認識します。
しかし必要なら、特定のプロパティに対して、直接のフィールドアクセスに切り替えることは可能です。
形式のメソッド名を認識します。
しかし必要なら、特定のプロパティに対して、直接のフィールドアクセスに切り替えることは可能です。
</para>
<para>
プロパティはpublicで宣言する必要は <emphasis>ありません</emphasis>
Hibernateはデフォルト、<literal>protected</literal> もしくは <literal>private</literal>
のget / setのペアを持つプロパティを永続化することができます。
プロパティはpublicで宣言する必要は <emphasis>ありません</emphasis>
Hibernateはデフォルト、<literal>protected</literal> もしくは <literal>private</literal>
のget / setのペアを持つプロパティを永続化することができます。
</para>
</sect2>
@ -213,11 +215,11 @@ public class Cat {
</sect1>
<sect1 id="persistent-classes-inheritance">
<title>継承の実装</title>
<title>継承の実装</title>
<para>
サブクラスも1番目と2番目のルールを守らなければなりません。
サブクラスはスーパークラス <literal>Cat</literal> から識別子プロパティを継承します。
サブクラスも1番目と2番目のルールを守らなければなりません。
サブクラスはスーパークラス <literal>Cat</literal> から識別子プロパティを継承します。
</para>
<programlisting><![CDATA[package eg;
@ -235,60 +237,60 @@ public class DomesticCat extends Cat {
</sect1>
<sect1 id="persistent-classes-equalshashcode" revision="1">
<title><literal>equals()</literal><literal>hashCode()</literal> の実装</title>
<title><literal>equals()</literal><literal>hashCode()</literal> の実装</title>
<para>
以下の条件の場合、
<literal>equals()</literal><literal>hashCode()</literal> メソッドをオーバーライドしなければなりません、
以下の条件の場合、
<literal>equals()</literal><literal>hashCode()</literal> メソッドをオーバーライドしなければなりません、
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
永続クラスのインスタンスを <literal>Set</literal> に置く場合。
(これは多値の関連を表現するおすすめの方法です)
<emphasis>そして同時に</emphasis>
永続クラスのインスタンスを <literal>Set</literal> に置く場合。
(これは多値の関連を表現するおすすめの方法です)
<emphasis>そして同時に</emphasis>
</para>
</listitem>
<listitem>
<para>
分離インスタンスをセッションへ再追加する場合。
分離インスタンスをセッションへ再追加する場合。
</para>
</listitem>
</itemizedlist>
<para>
Hibernateは、永続IDデータベースの行と、特定のセッションスコープ内に
限定ですがJavaIDとが等価であることを保証します。
ですから異なるセッションで検索したインスタンスを組み合わせる場合、
<literal>Set</literal> に意味のあるセマンティクスを持たせようと思っているなら
すぐに<literal>equals()</literal><literal>hashCode()</literal>
を実装しなければなりません。
Hibernateは、永続IDデータベースの行と、特定のセッションスコープ内に
限定ですがJavaIDとが等価であることを保証します。
ですから異なるセッションで検索したインスタンスを組み合わせる場合、
<literal>Set</literal> に意味のあるセマンティクスを持たせようと思っているなら
すぐに<literal>equals()</literal><literal>hashCode()</literal>
を実装しなければなりません。
</para>
<para>
最も明白な方法は、両方のオブジェクトの識別子の値の比較によって <literal>equals()</literal>
<literal>hashCode()</literal> を実装する方法です。
値が同じなら、両者はデータベースの同じ行でなければならないため等しくなります。
(両者が <literal>Set</literal> に追加されても、
<literal>Set</literal> には1個の要素しかないことになります
残念なことに、生成された識別子にはこのアプローチを使うことができません。
Hibernateは永続化されたオブジェクトへ識別子の値を代入するだけであり、
新しく作成されたインスタンスはどのような識別子の値も持っていません。
さらに、インスタンスがセーブされておらず、現在 <literal>Set</literal> の中にあれば、
セーブするとオブジェクトへ識別子の値を代入することになります。
もし <literal>equals()</literal><literal>hashCode()</literal> が識別子の値に基づいているなら、
ハッシュコードが変更されると <literal>Set</literal> の規約が破られます。
この問題についての完全な議論は、Hibernateのウェブサイトを見てください。
これはHibernateの問題ではなく、オブジェクトの同一性と等価性についての、
通常のJavaのセマンティクスであることに注意してください。
最も明白な方法は、両方のオブジェクトの識別子の値の比較によって <literal>equals()</literal>
<literal>hashCode()</literal> を実装する方法です。
値が同じなら、両者はデータベースの同じ行でなければならないため等しくなります。
(両者が <literal>Set</literal> に追加されても、
<literal>Set</literal> には1個の要素しかないことになります
残念なことに、生成された識別子にはこのアプローチを使うことができません。
Hibernateは永続化されたオブジェクトへ識別子の値を代入するだけであり、
新しく作成されたインスタンスはどのような識別子の値も持っていません。
さらに、インスタンスがセーブされておらず、現在 <literal>Set</literal> の中にあれば、
セーブするとオブジェクトへ識別子の値を代入することになります。
もし <literal>equals()</literal><literal>hashCode()</literal> が識別子の値に基づいているなら、
ハッシュコードが変更されると <literal>Set</literal> の規約が破られます。
この問題についての完全な議論は、Hibernateのウェブサイトを見てください。
これはHibernateの問題ではなく、オブジェクトの同一性と等価性についての、
通常のJavaのセマンティクスであることに注意してください。
</para>
<para>
<emphasis>ビジネスキーの等価性</emphasis> を使って、
<literal>equals()</literal><literal>hashCode()</literal> を実装することをお勧めします。
ビジネスキーの等価性とは、<literal>equals()</literal> メソッドが、ビジネスキー、
つまり現実の世界においてインスタンスを特定するキー(<emphasis>自然</emphasis> 候補キー)
を形成するプロパティだけを比較することを意味します。
<emphasis>ビジネスキーの等価性</emphasis> を使って、
<literal>equals()</literal><literal>hashCode()</literal> を実装することをお勧めします。
ビジネスキーの等価性とは、<literal>equals()</literal> メソッドが、ビジネスキー、
つまり現実の世界においてインスタンスを特定するキー(<emphasis>自然</emphasis> 候補キー)
を形成するプロパティだけを比較することを意味します。
</para>
<programlisting><![CDATA[public class Cat {
@ -316,39 +318,39 @@ public class DomesticCat extends Cat {
}]]></programlisting>
<para>
ビジネスキーはデータベースの主キー候補ほど安定である必要はないことに注意してください
<xref linkend="transactions-basics-identity"/> を見てください)。
更新不可なプロパティやユニークなプロパティは、通常ビジネスキーのよい候補です。
ビジネスキーはデータベースの主キー候補ほど安定である必要はないことに注意してください
<xref linkend="transactions-basics-identity"/> を見てください)。
更新不可なプロパティやユニークなプロパティは、通常ビジネスキーのよい候補です。
</para>
</sect1>
<sect1 id="persistent-classes-dynamicmodels">
<title>動的モデル</title>
<title>動的モデル</title>
<para>
<emphasis>以下の機能は現在実験段階にあると見なされており、
近い将来変更される可能性があることに注意してください。</emphasis>
<emphasis>以下の機能は現在実験段階にあると見なされており、
近い将来変更される可能性があることに注意してください。</emphasis>
</para>
<para>
永続エンティティは、必ずしも実行時にPOJOクラスやJavaBeanオブジェクトで表現する必要はありません。
Hibernateは実行時に <literal>Map</literal><literal>Map</literal> を使う)動的モデルと、
DOM4Jツリーとしてのエンティティの表現もサポートします。
このアプローチを使うと永続クラスを書かず、マッピングファイルだけを書くことになります。
永続エンティティは、必ずしも実行時にPOJOクラスやJavaBeanオブジェクトで表現する必要はありません。
Hibernateは実行時に <literal>Map</literal><literal>Map</literal> を使う)動的モデルと、
DOM4Jツリーとしてのエンティティの表現もサポートします。
このアプローチを使うと永続クラスを書かず、マッピングファイルだけを書くことになります。
</para>
<para>
デフォルトでは、Hibernateは通常のPOJOモードで動作します。
<literal>default_entity_mode</literal> 設定オプションを使って、
特定の <literal>SessionFactory</literal> に対するデフォルトのエンティティ表現モードを設定することができます
<xref linkend="configuration-optional-properties"/> を見てください)。
デフォルトでは、Hibernateは通常のPOJOモードで動作します。
<literal>default_entity_mode</literal> 設定オプションを使って、
特定の <literal>SessionFactory</literal> に対するデフォルトのエンティティ表現モードを設定することができます
<xref linkend="configuration-optional-properties"/> を見てください)。
</para>
<para>
以下の例では <literal>Map</literal> を使った表現を紹介します。
まずマッピングファイルで、クラス名の代わりに(またはそれに加えて)
<literal>entity-name</literal> を定義しなければなりません:
以下の例では <literal>Map</literal> を使った表現を紹介します。
まずマッピングファイルで、クラス名の代わりに(またはそれに加えて)
<literal>entity-name</literal> を定義しなければなりません:
</para>
<programlisting><![CDATA[<hibernate-mapping>
@ -386,14 +388,14 @@ public class DomesticCat extends Cat {
</hibernate-mapping>]]></programlisting>
<para>
関連がターゲットのクラス名を使って定義していたとしても、
関連のターゲット型もPOJOではなく動的なエンティティでも構わないことに注意してください。
関連がターゲットのクラス名を使って定義していたとしても、
関連のターゲット型もPOJOではなく動的なエンティティでも構わないことに注意してください。
</para>
<para>
<literal>SessionFactory</literal> に対してデフォルトのエンティティモードを
<literal>dynamic-map</literal> に設定した後、
実行時に <literal>Map</literal><literal>Map</literal> を使うことができます:
<literal>SessionFactory</literal> に対してデフォルトのエンティティモードを
<literal>dynamic-map</literal> に設定した後、
実行時に <literal>Map</literal><literal>Map</literal> を使うことができます:
</para>
<programlisting><![CDATA[Session s = openSession();
@ -419,15 +421,15 @@ tx.commit();
s.close();]]></programlisting>
<para>
動的なマッピングの利点は、エンティティクラスの実装を必要としないため、
プロトタイピングに要するターンアラウンドタイムが早いということです。
しかしコンパイル時の型チェックがないので、実行時に非常に多くの例外処理を扱わなければならないでしょう。
Hibernateマッピングのおかげで、データベーススキーマは容易に正規化でき、健全になり、
後で適切なドメインモデルの実装を追加することが可能になります。
動的なマッピングの利点は、エンティティクラスの実装を必要としないため、
プロトタイピングに要するターンアラウンドタイムが早いということです。
しかしコンパイル時の型チェックがないので、実行時に非常に多くの例外処理を扱わなければならないでしょう。
Hibernateマッピングのおかげで、データベーススキーマは容易に正規化でき、健全になり、
後で適切なドメインモデルの実装を追加することが可能になります。
</para>
<para>
エンティティ表現モードは <literal>Session</literal> ごとに設定することも可能です。
エンティティ表現モードは <literal>Session</literal> ごとに設定することも可能です。
</para>
<programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
@ -445,18 +447,18 @@ dynamicSession.close()
<para>
<literal>EntityMode</literal> を使った <literal>getSession()</literal>
の呼び出しは <literal>SessionFactory</literal> ではなく <literal>Session</literal>
APIにあることに注意してください。
その方法では、新しい <literal>Session</literal> は、ベースとなるJDBCコネクション、
トランザクション、その他のコンテキスト情報を共有します。
これは2番目の <literal>Session</literal> では <literal>flush()</literal><literal>close()</literal>
を呼ぶ必要がないということ、そのためトランザクションとコネクションの管理を
1番目の作業単位(Unit of Work)に任せることができるということです。
<literal>EntityMode</literal> を使った <literal>getSession()</literal>
の呼び出しは <literal>SessionFactory</literal> ではなく <literal>Session</literal>
APIにあることに注意してください。
その方法では、新しい <literal>Session</literal> は、ベースとなるJDBCコネクション、
トランザクション、その他のコンテキスト情報を共有します。
これは2番目の <literal>Session</literal> では <literal>flush()</literal><literal>close()</literal>
を呼ぶ必要がないということ、そのためトランザクションとコネクションの管理を
1番目の作業単位(Unit of Work)に任せることができるということです。
</para>
<para>
XML表現の能力についてのさらなる情報は <xref linkend="xml"/> で見つかります。
XML表現の能力についてのさらなる情報は <xref linkend="xml"/> で見つかります。
</para>
</sect1>
@ -465,30 +467,30 @@ dynamicSession.close()
<title>Tuplizer</title>
<para>
<literal>org.hibernate.tuple.Tuplizer</literal> とそのサブインターフェイスは、
表現の <literal>org.hibernate.EntityMode</literal> を利用して、
データ断片のある表現の管理に責任を持ちます。
与えられたデータ断片をデータ構造として考えるなら、Tuplizerはそのようなデータ構造を
どのように作成するかを知り、そのようなデータ構造からどのように値を抽出し、
注入するかを知っています。
例えばPOJOエンティティモードでは、対応するTuplizerはコンストラクタを通して、
POJOをどのように作成するか、定義されたプロパティアクセサを使い、
POJOプロパティにどのようにアクセスするかを知ります。
Tuplizerには二つのハイレベルの型があります。
それらは、<literal>org.hibernate.tuple.EntityTuplizer</literal>
<literal>org.hibernate.tuple.ComponentTuplizer</literal> インターフェイスで表現されます。
<literal>EntityTuplizer</literal> は上で述べたようなエンティティに関する契約の管理に責任を持ちます。
一方、<literal>ComponentTuplizer</literal> はコンポーネントに関する契約の管理に責任を持ちます。
<literal>org.hibernate.tuple.Tuplizer</literal> とそのサブインターフェイスは、
表現の <literal>org.hibernate.EntityMode</literal> を利用して、
データ断片のある表現の管理に責任を持ちます。
与えられたデータ断片をデータ構造として考えるなら、Tuplizerはそのようなデータ構造を
どのように作成するかを知り、そのようなデータ構造からどのように値を抽出し、
注入するかを知っています。
例えばPOJOエンティティモードでは、対応するTuplizerはコンストラクタを通して、
POJOをどのように作成するか、定義されたプロパティアクセサを使い、
POJOプロパティにどのようにアクセスするかを知ります。
Tuplizerには二つのハイレベルの型があります。
それらは、<literal>org.hibernate.tuple.EntityTuplizer</literal>
<literal>org.hibernate.tuple.ComponentTuplizer</literal> インターフェイスで表現されます。
<literal>EntityTuplizer</literal> は上で述べたようなエンティティに関する契約の管理に責任を持ちます。
一方、<literal>ComponentTuplizer</literal> はコンポーネントに関する契約の管理に責任を持ちます。
</para>
<para>
ユーザは独自のTuplizerに差し替えることも可能です。
おそらくdynamic-map entity-modeの際に <literal>java.util.HashMap</literal> を使うのではなく、
<literal>java.util.Map</literal> の実装が必要でしょう。
もしくは、おそらくデフォルトのものではなく、別のプロキシ生成戦略の定義が必要でしょう。
両者とも、カスタムのTuplizer実装を定義することで達成されます。
Tuplizerの定義は、管理しようとするエンティティやコンポーネントのマッピングに結び付けられます。
顧客エンティティの例に戻ると:
ユーザは独自のTuplizerに差し替えることも可能です。
おそらくdynamic-map entity-modeの際に <literal>java.util.HashMap</literal> を使うのではなく、
<literal>java.util.Map</literal> の実装が必要でしょう。
もしくは、おそらくデフォルトのものではなく、別のプロキシ生成戦略の定義が必要でしょう。
両者とも、カスタムのTuplizer実装を定義することで達成されます。
Tuplizerの定義は、管理しようとするエンティティやコンポーネントのマッピングに結び付けられます。
顧客エンティティの例に戻ると:
</para>
<programlisting><![CDATA[<hibernate-mapping>
@ -531,7 +533,7 @@ public class CustomMapTuplizerImpl
</sect1>
<para>
TODO: プロパティとプロキシパッケージのユーザ拡張フレームワークを文書化すること
TODO: プロパティとプロキシパッケージのユーザ拡張フレームワークを文書化すること
</para>
</chapter>

View File

@ -1,145 +1,144 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<preface id="preface" revision="2">
<title>前書き</title>
<title>前書き</title>
<para>
今日の企業環境において、オブジェクト指向ソフトウェアとリレーショナルデータベースに関わる作業は
煩雑で膨大な時間を必要とします。
HibernateはJava環境のオブジェクト/リレーショナルマッピングツールです。
オブジェクト/リレーショナルマッピングORMとは、
オブジェクトモデルからSQLベーススキーマのリレーショナルデータモデルへと、
データ表現をマッピングする(対応付ける)技術のことです。
今日の企業環境において、オブジェクト指向ソフトウェアとリレーショナルデータベースに関わる作業は
煩雑で膨大な時間を必要とします。
HibernateはJava環境のオブジェクト/リレーショナルマッピングツールです。
オブジェクト/リレーショナルマッピングORMとは、
オブジェクトモデルからSQLベーススキーマのリレーショナルデータモデルへと、
データ表現をマッピングする(対応付ける)技術のことです。
</para>
<para>
HibernateはJavaクラスからデータベーステーブルへそしてJavaデータ型からSQLデータ型へ
のマッピングを処理するだけではなく、データのクエリと復元の仕組みも提供します。
このおかげでSQLとJDBCを使った手作業でのデータ処理に費やされていた開発時間を大幅に削減できます。
HibernateはJavaクラスからデータベーステーブルへそしてJavaデータ型からSQLデータ型へ
のマッピングを処理するだけではなく、データのクエリと復元の仕組みも提供します。
このおかげでSQLとJDBCを使った手作業でのデータ処理に費やされていた開発時間を大幅に削減できます。
</para>
<para>
Hibernateの最終目標は、データの永続化に関わる一般的なプログラミング作業の95から開発者を解放することです。
Hibernateはビジネスロジックの実装にストアドプロシージャを使う
データ中心アプリケーションに対してのベストソリューションであるに留まりません。
オブジェクト指向ドメインモデルとJavaベースの中間層でのビジネスロジックに対して最も役に立ちます。
しかしHibernateはベンダ固有のSQLコードを削減またはカプセル化したり、
表形式からオブジェクトのグラフへとリザルトセットを変換するなどの、
一般的なタスクにも役立つでしょう。
Hibernateの最終目標は、データの永続化に関わる一般的なプログラミング作業の95から開発者を解放することです。
Hibernateはビジネスロジックの実装にストアドプロシージャを使う
データ中心アプリケーションに対してのベストソリューションであるに留まりません。
オブジェクト指向ドメインモデルとJavaベースの中間層でのビジネスロジックに対して最も役に立ちます。
しかしHibernateはベンダ固有のSQLコードを削減またはカプセル化したり、
表形式からオブジェクトのグラフへとリザルトセットを変換するなどの、
一般的なタスクにも役立つでしょう。
</para>
<para>
Hibernateやオブジェクト/リレーショナルマッピング、
さらにはJavaが初めての方は、以下のステップに従ってください
Hibernateやオブジェクト/リレーショナルマッピング、
さらにはJavaが初めての方は、以下のステップに従ってください
</para>
<orderedlist>
<listitem>
<para>
<xref linkend="tutorial"/> を読んでください。
段階的に解説していきます。
チュートリアルのソースコードはディストリビューションの
<literal>doc/reference/tutorial</literal> ディレクトリに含まれています。
<xref linkend="tutorial"/> を読んでください。
段階的に解説していきます。
チュートリアルのソースコードはディストリビューションの
<literal>doc/reference/tutorial</literal> ディレクトリに含まれています。
</para>
</listitem>
<listitem>
<para>
<xref linkend="architecture"/> を読んで、Hibernateが利用可能な環境を理解してください。
<xref linkend="architecture"/> を読んで、Hibernateが利用可能な環境を理解してください。
</para>
</listitem>
<listitem>
<para>
Hibernateディストリビューションの <literal>eg/</literal> ディレクトリを見てください。
簡単なスタンドアローンのアプリケーションがあります。
JDBCドライバを <literal>lib/</literal> ディレクトリにコピーして、
自分のデータベースに合う正しい値を指定するように <literal>etc/hibernate.properties</literal>
を編集してください。
ディストリビューションディレクトリから、コマンドプロンプトで
<literal>ant eg</literal> とタイプしてくださいAntを使います
またWindows環境では <literal>build eg</literal> とタイプしてください。
Hibernateディストリビューションの <literal>eg/</literal> ディレクトリを見てください。
簡単なスタンドアローンのアプリケーションがあります。
JDBCドライバを <literal>lib/</literal> ディレクトリにコピーして、
自分のデータベースに合う正しい値を指定するように <literal>etc/hibernate.properties</literal>
を編集してください。
ディストリビューションディレクトリから、コマンドプロンプトで
<literal>ant eg</literal> とタイプしてくださいAntを使います
またWindows環境では <literal>build eg</literal> とタイプしてください。
</para>
</listitem>
<listitem>
<para>
このリファレンスドキュメントを第一の情報源として利用してください。
アプリケーション設計についてのさらなる情報や段階的なチュートリアルを探しているなら、
<emphasis>Java Persistence with Hibernate</emphasis>http://www.manning.com/bauer2
をおすすめします。
またhttp://caveatemptor.hibernate.orgから
Java Persistence with Hibernateの例題のアプリケーションをダウンロードできます。
このリファレンスドキュメントを第一の情報源として利用してください。
アプリケーション設計についてのさらなる情報や段階的なチュートリアルを探しているなら、
<emphasis>Java Persistence with Hibernate</emphasis>http://www.manning.com/bauer2
をおすすめします。
またhttp://caveatemptor.hibernate.orgから
Java Persistence with Hibernateの例題のアプリケーションをダウンロードできます。
</para>
</listitem>
<listitem>
<para>
FAQはHibernateウェブサイトにあります。
FAQはHibernateウェブサイトにあります。
</para>
</listitem>
<listitem>
<para>
サードパーティのデモ、例、チュートリアルはHibernateウェブサイトにリンクがあります。
サードパーティのデモ、例、チュートリアルはHibernateウェブサイトにリンクがあります。
</para>
</listitem>
<listitem>
<para>
Hibernateウェブサイトのコミュニティエリアは、デザインパターンやさまざまな統合ソリューション
Tomcat, JBoss AS, Struts, EJB, 等)についてのよい情報源です。
Hibernateウェブサイトのコミュニティエリアは、デザインパターンやさまざまな統合ソリューション
Tomcat, JBoss AS, Struts, EJB, 等)についてのよい情報源です。
</para>
</listitem>
</orderedlist>
<para>
質問があればHibernateウェブサイトのユーザフォーラムを活用してください。
またバグレポートとフィーチャリクエストのためJIRA課題追跡システムを用意しています。
Hibernateの開発に興味があれば、開発者メーリングリストに参加してください。
このドキュメントをあなたの国の言葉に翻訳したい場合は、
開発者メーリングリストで私たちにコンタクトを取ってください。
質問があればHibernateウェブサイトのユーザフォーラムを活用してください。
またバグレポートとフィーチャリクエストのためJIRA課題追跡システムを用意しています。
Hibernateの開発に興味があれば、開発者メーリングリストに参加してください。
このドキュメントをあなたの国の言葉に翻訳したい場合は、
開発者メーリングリストで私たちにコンタクトを取ってください。
</para>
<para>
商用開発のサポート、製品のサポート、HibernateのトレーニングはJBoss Inc.が提供しています
http://www.hibernate.org/SupportTraining/を見てください)。
HibernateはProfessional Open Sourceプロジェクト、
そしてJBoss Enterprise Middleware SystemJEMSプロダクトスイートのクリティカルコンポーネントです。
商用開発のサポート、製品のサポート、HibernateのトレーニングはJBoss Inc.が提供しています
http://www.hibernate.org/SupportTraining/を見てください)。
HibernateはProfessional Open Sourceプロジェクト、
そしてJBoss Enterprise Middleware SystemJEMSプロダクトスイートのクリティカルコンポーネントです。
</para>
<!--
<sect1 id="preface-s1" revision="-1">
<title>日本語訳について</title>
<title>日本語訳について</title>
<para id="preface-s1-p1" revision="-1">
この日本語版Hibernate Reference Document以下、日本語版は、
Hibernateプロジェクトの翻訳プロセスに基づいて作成されています。
日本語版ならびに原文はLGPLライセンスに準じます。
この日本語版Hibernate Reference Document以下、日本語版は、
Hibernateプロジェクトの翻訳プロセスに基づいて作成されています。
日本語版ならびに原文はLGPLライセンスに準じます。
</para>
<para id="preface-s1-p2" revision="-1">
日本語版の利用によって第三者が被るあらゆる不利益に対して、
原著者、翻訳者ならびにその組織は一切の保証をいたしかねます。
日本語版は誤りを含む可能性があることを認識した上でご利用ください。
内容の正確な意味を把握するためには、原文を読むことをおすすめします。
また、もし日本語版に誤りを見つけられた場合は、翻訳者にご連絡いただければ幸いです。
ただし内容に関してのお問い合わせには応じかねますので、ご了承ください。
日本語版の利用によって第三者が被るあらゆる不利益に対して、
原著者、翻訳者ならびにその組織は一切の保証をいたしかねます。
日本語版は誤りを含む可能性があることを認識した上でご利用ください。
内容の正確な意味を把握するためには、原文を読むことをおすすめします。
また、もし日本語版に誤りを見つけられた場合は、翻訳者にご連絡いただければ幸いです。
ただし内容に関してのお問い合わせには応じかねますので、ご了承ください。
</para>
<sect2 id="preface-s1-1" revision="-1">
<title>日本語版翻訳者について</title>
<title>日本語版翻訳者について</title>
<para id="preface-s1-1-p4" revision="-1">
日本語版バージョン3.2 cr3の翻訳は株式会社エクサ
<ulink url="http://www.exa-corp.co.jp">ホームページはこちら</ulink>
の以下のメンバーで行いました。
本間力6,18,19,21,22,23章担当
広戸裕介(前書き,2,5,13,14,24,25章担当
武市正人7,8,9,10章担当
那須秀男12,16,17章担当
井関知文1,3,11章担当
飯田浩司4,15章担当
平間健一20章担当
森龍二(レビュー担当)。
なお誤訳等のご指摘は本間、広戸までお願いいたします。
日本語版バージョン3.2 cr3の翻訳は株式会社エクサ
<ulink url="http://www.exa-corp.co.jp">ホームページはこちら</ulink>
の以下のメンバーで行いました。
本間力6,18,19,21,22,23章担当
広戸裕介(前書き,2,5,13,14,24,25章担当
武市正人7,8,9,10章担当
那須秀男12,16,17章担当
井関知文1,3,11章担当
飯田浩司4,15章担当
平間健一20章担当
森龍二(レビュー担当)。
なお誤訳等のご指摘は本間、広戸までお願いいたします。
<mediaobject>
<imageobject role="fo">
@ -154,4 +153,4 @@
</sect2>
</sect1>
-->
</preface>
</preface>

View File

@ -1,18 +1,20 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="querycriteria">
<title>Criteriaクエリ</title>
<title>Criteriaクエリ</title>
<para>
Hibernateには、直感的で拡張可能なcriteriaクエリAPIが用意されています。
Hibernateには、直感的で拡張可能なcriteriaクエリAPIが用意されています。
</para>
<sect1 id="querycriteria-creating">
<title> <literal>Criteria</literal> インスタンスの作成</title>
<title> <literal>Criteria</literal> インスタンスの作成</title>
<para>
<literal>org.hibernate.Criteria</literal>
インターフェイスは特定の永続性クラスに対するクエリを表現します。
<literal>Session</literal><literal>Criteria</literal> インスタンスのファクトリです。
インターフェイスは特定の永続性クラスに対するクエリを表現します。
<literal>Session</literal><literal>Criteria</literal> インスタンスのファクトリです。
</para>
<programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
@ -22,14 +24,14 @@ List cats = crit.list();]]></programlisting>
</sect1>
<sect1 id="querycriteria-narrowing">
<title>リザルトセットの絞込み</title>
<title>リザルトセットの絞込み</title>
<para>
<literal>org.hibernate.criterion.Criterion</literal> インターフェイスのインスタンスは、
個別のクエリクライテリオン(問い合わせの判定基準)を表します。
<literal>org.hibernate.criterion.Criterion</literal> インターフェイスのインスタンスは、
個別のクエリクライテリオン(問い合わせの判定基準)を表します。
<literal>org.hibernate.criterion.Restrictions</literal>
クラスは、ある組み込みの <literal>Criterion</literal>
型を取得するためのファクトリメソッドを持っています。
クラスは、ある組み込みの <literal>Criterion</literal>
型を取得するためのファクトリメソッドを持っています。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -38,7 +40,7 @@ List cats = crit.list();]]></programlisting>
.list();]]></programlisting>
<para>
Restriction限定は、論理的にグループ化できます。
Restriction限定は、論理的にグループ化できます。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -60,8 +62,8 @@ List cats = crit.list();]]></programlisting>
.list();]]></programlisting>
<para>
元々あるCriterion型<literal>Restrictions</literal> のサブクラス)
はかなりの範囲に及びますが、特に有用なのはSQLを直接指定できるものです。
元々あるCriterion型<literal>Restrictions</literal> のサブクラス)
はかなりの範囲に及びますが、特に有用なのはSQLを直接指定できるものです。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -69,15 +71,15 @@ List cats = crit.list();]]></programlisting>
.list();]]></programlisting>
<para>
<literal>{alias}</literal> というプレースホルダは、
問い合わせを受けたエンティティの行の別名によって置き換えられます。
<literal>{alias}</literal> というプレースホルダは、
問い合わせを受けたエンティティの行の別名によって置き換えられます。
</para>
<para>
criterionを得る別の手段は、
<literal>Property</literal> インスタンスから取得することです。
<literal>Property.forName()</literal> を呼び出して、
<literal>Property</literal> インスタンスを作成できます。
criterionを得る別の手段は、
<literal>Property</literal> インスタンスから取得することです。
<literal>Property.forName()</literal> を呼び出して、
<literal>Property</literal> インスタンスを作成できます。
</para>
<programlisting><![CDATA[
@ -95,11 +97,11 @@ List cats = sess.createCriteria(Cat.class)
</sect1>
<sect1 id="querycriteria-ordering">
<title>結果の整列</title>
<title>結果の整列</title>
<para>
<literal>org.hibernate.criterion.Order</literal>
を使って結果を並び替えることができます。
を使って結果を並び替えることができます。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -119,11 +121,11 @@ List cats = sess.createCriteria(Cat.class)
</sect1>
<sect1 id="querycriteria-associations" revision="2">
<title>関連</title>
<title>関連</title>
<para>
<literal>createCriteria()</literal> を使い、関連をナビゲートすることで、
容易に関係するエンティティに制約を指定できます。
<literal>createCriteria()</literal> を使い、関連をナビゲートすることで、
容易に関係するエンティティに制約を指定できます。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -133,13 +135,13 @@ List cats = sess.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
2番目の <literal>createCriteria()</literal> は、<literal>kittens</literal>
コレクションの要素を参照する新しい <literal>Criteria</literal>
インスタンスを返すことに注意してください。
2番目の <literal>createCriteria()</literal> は、<literal>kittens</literal>
コレクションの要素を参照する新しい <literal>Criteria</literal>
インスタンスを返すことに注意してください。
</para>
<para>
以下のような方法も、状況により有用です。
以下のような方法も、状況により有用です。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -149,17 +151,17 @@ List cats = sess.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
<literal>createAlias()</literal> は新しい
<literal>Criteria</literal> インスタンスを作成しません。)
<literal>createAlias()</literal> は新しい
<literal>Criteria</literal> インスタンスを作成しません。)
</para>
<para>
前の2つのクエリによって返される <literal>Cat</literal>
インスタンスによって保持されるkittensコレクションは、
criteriaによって事前にフィルタリング <emphasis>されない</emphasis>
ことに注意してください。
もしcriteriaに適合するkittenを取得したいなら、
<literal>ResultTransformer</literal> を使わなければなりません。
前の2つのクエリによって返される <literal>Cat</literal>
インスタンスによって保持されるkittensコレクションは、
criteriaによって事前にフィルタリング <emphasis>されない</emphasis>
ことに注意してください。
もしcriteriaに適合するkittenを取得したいなら、
<literal>ResultTransformer</literal> を使わなければなりません。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -177,11 +179,11 @@ while ( iter.hasNext() ) {
</sect1>
<sect1 id="querycriteria-dynamicfetching" revision="1">
<title>関連の動的フェッチ</title>
<title>関連の動的フェッチ</title>
<para>
<literal>setFetchMode()</literal> を使い、
実行時に関連の復元方法を指定してもよいです。
<literal>setFetchMode()</literal> を使い、
実行時に関連の復元方法を指定してもよいです。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
@ -191,19 +193,19 @@ while ( iter.hasNext() ) {
.list();]]></programlisting>
<para>
このクエリは外部結合により <literal>mate</literal>
<literal>kittens</literal> の両方をフェッチします。
より多くの情報は <xref linkend="performance-fetching"/> を参照してください。
このクエリは外部結合により <literal>mate</literal>
<literal>kittens</literal> の両方をフェッチします。
より多くの情報は <xref linkend="performance-fetching"/> を参照してください。
</para>
</sect1>
<sect1 id="querycriteria-examples">
<title>クエリの例</title>
<title>クエリの例</title>
<para>
<literal>org.hibernate.criterion.Example</literal> クラスは、
与えられたインスタンスからクエリクライテリオンを構築できます。
<literal>org.hibernate.criterion.Example</literal> クラスは、
与えられたインスタンスからクエリクライテリオンを構築できます。
</para>
<programlisting><![CDATA[Cat cat = new Cat();
@ -214,13 +216,13 @@ List results = session.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
バージョンプロパティ、識別子、関連は無視されます。
デフォルトではnull値のプロパティは除外されます。
バージョンプロパティ、識別子、関連は無視されます。
デフォルトではnull値のプロパティは除外されます。
</para>
<para>
どのように <literal>Example</literal> を適用するか
調整することができます。
どのように <literal>Example</literal> を適用するか
調整することができます。
</para>
<programlisting><![CDATA[Example example = Example.create(cat)
@ -233,7 +235,7 @@ List results = session.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
関連オブジェクトにcriteriaを指定するために、Exampleを使うことも可能です。
関連オブジェクトにcriteriaを指定するために、Exampleを使うことも可能です。
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
@ -245,12 +247,12 @@ List results = session.createCriteria(Cat.class)
</sect1>
<sect1 id="querycriteria-projection">
<title>射影、集約、グループ化</title>
<title>射影、集約、グループ化</title>
<para>
<literal>org.hibernate.criterion.Projections</literal> クラスは
<literal>Projection</literal> インスタンスのファクトリです。
<literal>setProjection()</literal> を呼び出すことで、
クエリに射影を適用します。
<literal>org.hibernate.criterion.Projections</literal> クラスは
<literal>Projection</literal> インスタンスのファクトリです。
<literal>setProjection()</literal> を呼び出すことで、
クエリに射影を適用します。
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
@ -268,14 +270,14 @@ List results = session.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
必要であっても、criteriaクエリに「group by」を明示する必要はありません。
ある種のProjection型は <emphasis>グループ化射影</emphasis> として定義され、
SQLの <literal>group by</literal> 節にも現れます。
必要であっても、criteriaクエリに「group by」を明示する必要はありません。
ある種のProjection型は <emphasis>グループ化射影</emphasis> として定義され、
SQLの <literal>group by</literal> 節にも現れます。
</para>
<para>
任意で射影に別名を付けられるため、射影される値はrestrictionやordering内から参照できます。
別名をつける2つの異なる方法を示します。
任意で射影に別名を付けられるため、射影される値はrestrictionやordering内から参照できます。
別名をつける2つの異なる方法を示します。
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
@ -289,10 +291,10 @@ List results = session.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
<literal>alias()</literal><literal>as()</literal> メソッドは、
Projectionインスタンスを別の名前の <literal>Projection</literal> インスタンスで
ラップするだけです。
ショートカットとして、射影を射影リストに追加する際に、別名をつけられます。
<literal>alias()</literal><literal>as()</literal> メソッドは、
Projectionインスタンスを別の名前の <literal>Projection</literal> インスタンスで
ラップするだけです。
ショートカットとして、射影を射影リストに追加する際に、別名をつけられます。
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
@ -317,7 +319,7 @@ List results = session.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
射影の式に <literal>Property.forName()</literal> も使用できます。
射影の式に <literal>Property.forName()</literal> も使用できます。
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
@ -339,11 +341,11 @@ List results = session.createCriteria(Cat.class)
</sect1>
<sect1 id="querycriteria-detachedqueries">
<title>クエリおよびサブクエリの分離</title>
<title>クエリおよびサブクエリの分離</title>
<para>
<literal>DetachedCriteria</literal> クラスにより、
セッションスコープ外にクエリを作成できます。
後で、任意の <literal>Session</literal> を使って、実行できます。
<literal>DetachedCriteria</literal> クラスにより、
セッションスコープ外にクエリを作成できます。
後で、任意の <literal>Session</literal> を使って、実行できます。
</para>
<programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
@ -356,9 +358,9 @@ txn.commit();
session.close();]]></programlisting>
<para>
<literal>DetachedCriteria</literal> は、サブクエリを表現するためにも使えます。
サブクエリを伴うCriterionインスタンスは、
<literal>Subqueries</literal> もしくは <literal>Property</literal> から得られます。
<literal>DetachedCriteria</literal> は、サブクエリを表現するためにも使えます。
サブクエリを伴うCriterionインスタンスは、
<literal>Subqueries</literal> もしくは <literal>Property</literal> から得られます。
</para>
<programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
@ -374,7 +376,7 @@ session.createCriteria(Cat.class)
.list();]]></programlisting>
<para>
相互関係があるサブクエリでさえも可能です。
相互関係があるサブクエリでさえも可能です。
</para>
<programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
@ -391,23 +393,23 @@ session.createCriteria(Cat.class, "cat")
could also be explained. -->
<sect1 id="query-criteria-naturalid">
<title>自然識別子によるクエリ</title>
<title>自然識別子によるクエリ</title>
<para>
criteriaクエリを含むたいていのクエリにとって、
クエリキャッシュはあまり効率がよくないです。
なぜなら、クエリキャッシュが頻繁に無効になるためです。
しかしながら、キャッシュを無効にするアルゴリズムを最適化できる
特別なクエリの種類が1つあります。
更新されない自然キーによる検索です。
いくつかのアプリケーションでは、この種類のクエリが頻繁に現れます。
このような使われ方のために、criteria APIは特別な対策を提供します。
criteriaクエリを含むたいていのクエリにとって、
クエリキャッシュはあまり効率がよくないです。
なぜなら、クエリキャッシュが頻繁に無効になるためです。
しかしながら、キャッシュを無効にするアルゴリズムを最適化できる
特別なクエリの種類が1つあります。
更新されない自然キーによる検索です。
いくつかのアプリケーションでは、この種類のクエリが頻繁に現れます。
このような使われ方のために、criteria APIは特別な対策を提供します。
</para>
<para>
最初に、<literal>&lt;natural-id&gt;</literal> を使って、
エンティティの自然キーをマップしてください。
そして、二次キャッシュを有効にします。
最初に、<literal>&lt;natural-id&gt;</literal> を使って、
エンティティの自然キーをマップしてください。
そして、二次キャッシュを有効にします。
</para>
<programlisting><![CDATA[<class name="User">
@ -423,17 +425,17 @@ session.createCriteria(Cat.class, "cat")
</class>]]></programlisting>
<para>
注意: <emphasis>変更される</emphasis> 自然キーを持つエンティティに
この機能を使うのは、意図されていない使い方です。
注意: <emphasis>変更される</emphasis> 自然キーを持つエンティティに
この機能を使うのは、意図されていない使い方です。
</para>
<para>
次に、Hibernateクエリキャッシュを有効にします。
次に、Hibernateクエリキャッシュを有効にします。
</para>
<para>
これで、<literal>Restrictions.naturalId()</literal> により、
より効率的なキャッシュアルゴリズムを使用できます。
これで、<literal>Restrictions.naturalId()</literal> により、
より効率的なキャッシュアルゴリズムを使用できます。
</para>
<programlisting><![CDATA[session.createCriteria(User.class)

View File

@ -1,41 +1,43 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="querysql" revision="2">
<title>ネイティブSQL</title>
<title>ネイティブSQL</title>
<para>データベースのネイティブSQL方言を使ってクエリを表現することもできます。
クエリヒントやOracleの <literal>CONNECT</literal> キーワードのように、
データベース独自の機能を利用したいときに使えます。
SQL/JDBCを直接使用しているアプリケーションからHibernateへの移行も容易にしています。</para>
<para>データベースのネイティブSQL方言を使ってクエリを表現することもできます。
クエリヒントやOracleの <literal>CONNECT</literal> キーワードのように、
データベース独自の機能を利用したいときに使えます。
SQL/JDBCを直接使用しているアプリケーションからHibernateへの移行も容易にしています。</para>
<para>Hibernate3では、生成、更新、削除、読み込み処理のようなすべての
SQLストアドプロシージャを含むを手書きできます。</para>
<para>Hibernate3では、生成、更新、削除、読み込み処理のようなすべての
SQLストアドプロシージャを含むを手書きできます。</para>
<sect1 id="querysql-creating" revision="4">
<title><literal>SQLQuery</literal> の使用</title>
<title><literal>SQLQuery</literal> の使用</title>
<para>ネイティブなSQLクエリの実行は <literal>SQLQuery</literal>
インターフェイスを通して制御します。
<literal>SQLQuery</literal> インターフェイスは
<literal>Session.createSQLQuery()</literal> を呼び出して取得します。
このAPIを使って問い合わせする方法を以下で説明します。</para>
<para>ネイティブなSQLクエリの実行は <literal>SQLQuery</literal>
インターフェイスを通して制御します。
<literal>SQLQuery</literal> インターフェイスは
<literal>Session.createSQLQuery()</literal> を呼び出して取得します。
このAPIを使って問い合わせする方法を以下で説明します。</para>
<sect2>
<title>スカラーのクエリ</title>
<title>スカラーのクエリ</title>
<para>最も基本的なSQLクエリはスカラーのリストを得ることです。</para>
<para>最も基本的なSQLクエリはスカラーのリストを得ることです。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
]]></programlisting>
<para>これらはどちらも、CATSテーブルの各カラムのスカラー値を含む
Object配列Object[])のリストを返します。
返すスカラー値の実際の順番と型を推定するために、
HibernateはResultSetMetadataを使用します。</para>
<para>これらはどちらも、CATSテーブルの各カラムのスカラー値を含む
Object配列Object[])のリストを返します。
返すスカラー値の実際の順番と型を推定するために、
HibernateはResultSetMetadataを使用します。</para>
<para><literal>ResultSetMetadata</literal> を使用するオーバーヘッドを避けるため、
もしくは単に何が返されるか明確にするため、<literal>addScalar()</literal>
を使えます。</para>
<para><literal>ResultSetMetadata</literal> を使用するオーバーヘッドを避けるため、
もしくは単に何が返されるか明確にするため、<literal>addScalar()</literal>
を使えます。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
.addScalar("ID", Hibernate.LONG)
@ -43,28 +45,28 @@ sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
.addScalar("BIRTHDATE", Hibernate.DATE)
]]></programlisting>
<para>このクエリで指定されているものを下記に示します。</para>
<para>このクエリで指定されているものを下記に示します。</para>
<itemizedlist>
<listitem>
<para>SQLクエリ文字列</para>
<para>SQLクエリ文字列</para>
</listitem>
<listitem>
<para>返されるカラムと型</para>
<para>返されるカラムと型</para>
</listitem>
</itemizedlist>
<para>これはまだObject配列を返しますが、
<literal>ResultSetMetdata</literal> を使用しません。
ただし、その代わりに基礎にあるリザルトセットから
ID、NAME、BIRTHDATE カラムをそれぞれ
Long、String、Short として明示的に取得します。
これは3つのカラムを返すのみであることも意味します。
たとえ、クエリが <literal>*</literal> を使用し、
列挙した3つより多くのカラムを返せるとしてもです。</para>
<para>これはまだObject配列を返しますが、
<literal>ResultSetMetdata</literal> を使用しません。
ただし、その代わりに基礎にあるリザルトセットから
ID、NAME、BIRTHDATE カラムをそれぞれ
Long、String、Short として明示的に取得します。
これは3つのカラムを返すのみであることも意味します。
たとえ、クエリが <literal>*</literal> を使用し、
列挙した3つより多くのカラムを返せるとしてもです。</para>
<para>スカラーの型情報を省くこともできます。</para>
<para>スカラーの型情報を省くこともできます。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
.addScalar("ID", Hibernate.LONG)
@ -73,68 +75,68 @@ sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
]]></programlisting>
<para>
これは本質的に前と同じクエリですが、、
NAME と BIRTHDATE の型を決めるために <literal>ResultSetMetaData</literal>
を使用します。一方、ID の型は明示的に指定されています。
これは本質的に前と同じクエリですが、、
NAME と BIRTHDATE の型を決めるために <literal>ResultSetMetaData</literal>
を使用します。一方、ID の型は明示的に指定されています。
</para>
<para>
ResultSetMetaData から返される java.sql.Types を Hibernate の型に
マッピングすることは、Dialect が制御します。
明示された型がマッピングされていないか、結果の型が期待したものと異なる場合、
Dialect の <literal>registerHibernateType</literal> を呼び出し、
カスタマイズできます。
ResultSetMetaData から返される java.sql.Types を Hibernate の型に
マッピングすることは、Dialect が制御します。
明示された型がマッピングされていないか、結果の型が期待したものと異なる場合、
Dialect の <literal>registerHibernateType</literal> を呼び出し、
カスタマイズできます。
</para>
</sect2>
<sect2>
<title>エンティティのクエリ</title>
<title>エンティティのクエリ</title>
<para>ここまでのクエリは、すべてスカラー値を返すものでした。
基本的に、リザルトセットから「未加工」の値を返します。
以降では、<literal>addEntity()</literal> により、ネイティブSQLクエリから
エンティティオブジェクトを取得する方法を示します。</para>
<para>ここまでのクエリは、すべてスカラー値を返すものでした。
基本的に、リザルトセットから「未加工」の値を返します。
以降では、<literal>addEntity()</literal> により、ネイティブSQLクエリから
エンティティオブジェクトを取得する方法を示します。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
]]></programlisting>
<para>このクエリで指定されているものを下記に示します。</para>
<para>このクエリで指定されているものを下記に示します。</para>
<itemizedlist>
<listitem>
<para>SQLクエリ文字列</para>
<para>SQLクエリ文字列</para>
</listitem>
<listitem>
<para>クエリが返すエンティティとSQLテーブルの別名
<para>クエリが返すエンティティとSQLテーブルの別名
</para>
</listitem>
</itemizedlist>
<para>CatがID, NAME, BIRTHDATEのカラムを使ってクラスにマッピングされる場合、
上記のクエリはどちらも、要素がCatエンティティであるリストを返します。</para>
<para>CatがID, NAME, BIRTHDATEのカラムを使ってクラスにマッピングされる場合、
上記のクエリはどちらも、要素がCatエンティティであるリストを返します。</para>
<para>エンティティを別のエンティティに <literal>多対一</literal> でマッピングしている場合は、
ネイティブクエリを実行する際に、この別のエンティティを返すことも要求します。
さもなければ、データベース固有の「column not found(カラムが見つかりません)」エラーが発生します。
* 表記を使用した際は、追加のカラムが自動的に返されますが、
次の例のように、<literal>Dog</literal><literal>多対一</literal> であることを
明示することを私たちは好みます。</para>
<para>エンティティを別のエンティティに <literal>多対一</literal> でマッピングしている場合は、
ネイティブクエリを実行する際に、この別のエンティティを返すことも要求します。
さもなければ、データベース固有の「column not found(カラムが見つかりません)」エラーが発生します。
* 表記を使用した際は、追加のカラムが自動的に返されますが、
次の例のように、<literal>Dog</literal><literal>多対一</literal> であることを
明示することを私たちは好みます。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
]]></programlisting>
<para>これにより cat.getDog() が正しく機能します。</para>
<para>これにより cat.getDog() が正しく機能します。</para>
</sect2>
<sect2>
<title>関連とコレクションの操作</title>
<title>関連とコレクションの操作</title>
<para>プロキシを初期化するための余分な処理を避けるため、
<literal>Dog</literal> の中で即時結合できます。
これは <literal>addJoin()</literal> メソッドにより行います。
関連もしくはコレクションに結合できます。
<para>プロキシを初期化するための余分な処理を避けるため、
<literal>Dog</literal> の中で即時結合できます。
これは <literal>addJoin()</literal> メソッドにより行います。
関連もしくはコレクションに結合できます。
</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
@ -142,79 +144,79 @@ sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class)
.addJoin("cat.dog");
]]></programlisting>
<para>この例の中で、返される <literal>Cat</literal> は、
データベースへの余分処理なしで、
完全に初期化された <literal>dog</literal> プロパティを持ちます。
結合対象のプロパティへのパスを指定できるように、
別名「cat」を追加したことに注意してください。
コレクションの即時結合も同じようにできます。
たとえば、<literal>Cat</literal> が一対多で <literal>Dog</literal>
を持っていた場合、次のようになります。</para>
<para>この例の中で、返される <literal>Cat</literal> は、
データベースへの余分処理なしで、
完全に初期化された <literal>dog</literal> プロパティを持ちます。
結合対象のプロパティへのパスを指定できるように、
別名「cat」を追加したことに注意してください。
コレクションの即時結合も同じようにできます。
たとえば、<literal>Cat</literal> が一対多で <literal>Dog</literal>
を持っていた場合、次のようになります。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
.addEntity("cat", Cat.class)
.addJoin("cat.dogs");
]]></programlisting>
<para>現在のところ、
Hibernateで使いやすくするためのSQLクエリの拡張なしに、
ネイティブクエリで何かを可能にする限界に来ています。
同じ型のエンティティを複数返す際や、デフォルトの別名や列名で十分ではない場合に、
問題は起こり始めます。
<para>現在のところ、
Hibernateで使いやすくするためのSQLクエリの拡張なしに、
ネイティブクエリで何かを可能にする限界に来ています。
同じ型のエンティティを複数返す際や、デフォルトの別名や列名で十分ではない場合に、
問題は起こり始めます。
</para>
</sect2>
<sect2>
<title>複数エンティティの取得</title>
<title>複数エンティティの取得</title>
<para>ここまでは、リザルトセットのカラム名は、
マッピングファイルで指定されたカラム名と同じであると仮定していました。
複数のテーブルが同じカラム名を持つ場合があるため、
複数テーブルを結合するSQLクエリで問題となる場合があります。</para>
<para>ここまでは、リザルトセットのカラム名は、
マッピングファイルで指定されたカラム名と同じであると仮定していました。
複数のテーブルが同じカラム名を持つ場合があるため、
複数テーブルを結合するSQLクエリで問題となる場合があります。</para>
<para>下記のような(失敗しそうな)クエリでは、
カラム別名インジェクションcolumn alias injectionが必要です。</para>
<para>下記のような(失敗しそうな)クエリでは、
カラム別名インジェクションcolumn alias injectionが必要です。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)
]]></programlisting>
<para>このクエリの意図は、
行ごとにつのCatインスタンス、つまり猫とその母親を返すということです。
同じカラム名にマッピングすることにより名前が衝突するため、このクエリは失敗します。
ベータベースによっては、返されるカラムの別名が "c.ID"、"c.NAME" などの形式であり、
マッピングで指定されたカラム("ID" と "NAME")と等しくないため、失敗します。</para>
<para>このクエリの意図は、
行ごとにつのCatインスタンス、つまり猫とその母親を返すということです。
同じカラム名にマッピングすることにより名前が衝突するため、このクエリは失敗します。
ベータベースによっては、返されるカラムの別名が "c.ID"、"c.NAME" などの形式であり、
マッピングで指定されたカラム("ID" と "NAME")と等しくないため、失敗します。</para>
<para>下記の形式は、カラム名が重複しても大丈夫です。</para>
<para>下記の形式は、カラム名が重複しても大丈夫です。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)
]]></programlisting>
<para>このクエリで指定されているものを下記に示します。</para>
<para>このクエリで指定されているものを下記に示します。</para>
<itemizedlist>
<listitem>
<para>SQLクエリ文字列
Hibernateがカラムの別名を挿入するためのプレースホルダを含む</para>
<para>SQLクエリ文字列
Hibernateがカラムの別名を挿入するためのプレースホルダを含む</para>
</listitem>
<listitem>
<para>クエリによって返されるエンティティ</para>
<para>クエリによって返されるエンティティ</para>
</listitem>
</itemizedlist>
<para>上記で使用している {cat.*} と {mother.*} という表記は、
「すべてのプロパティ」を表す省略形です。
代わりに、明示的にカラムを列挙してもよいですが、
その場合は、Hibernateに各プロパティに対応するSQLカラムの別名を挿入させるべきでしょう。
カラムの別名のためのプレースホルダは、テーブルの別名によって修飾されたプロパティ名です。
下記の例では、別のテーブル cat_log から
マッピングメタデータで定義された Cat とその母親を復元します。
もし好むなら、where節の中でも、プロパティの別名を使えます。</para>
<para>上記で使用している {cat.*} と {mother.*} という表記は、
「すべてのプロパティ」を表す省略形です。
代わりに、明示的にカラムを列挙してもよいですが、
その場合は、Hibernateに各プロパティに対応するSQLカラムの別名を挿入させるべきでしょう。
カラムの別名のためのプレースホルダは、テーブルの別名によって修飾されたプロパティ名です。
下記の例では、別のテーブル cat_log から
マッピングメタデータで定義された Cat とその母親を復元します。
もし好むなら、where節の中でも、プロパティの別名を使えます。</para>
<programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
@ -226,19 +228,19 @@ List loggedCats = sess.createSQLQuery(sql)
]]></programlisting>
<sect3 id="querysql-aliasreferences" revision="2">
<title>別名とプロパティのリファレンス</title>
<title>別名とプロパティのリファレンス</title>
<para>多くの場合、上記のような別名インジェクションが必要です。
ただし、複合プロパティ、継承識別子、コレクションなどのような
より複雑なマッピングと関連するクエリがなければです。
ある特定の別名を使用することにより、Hibernateは適切な別名を挿入できます。</para>
<para>多くの場合、上記のような別名インジェクションが必要です。
ただし、複合プロパティ、継承識別子、コレクションなどのような
より複雑なマッピングと関連するクエリがなければです。
ある特定の別名を使用することにより、Hibernateは適切な別名を挿入できます。</para>
<para>別名インジェクションとして使用できるものを下表に示します。
注意:下表の別名は一例です。
それぞれの別名は一意であり、使用する際にはおそらく異なる名前を持ちます。</para>
<para>別名インジェクションとして使用できるものを下表に示します。
注意:下表の別名は一例です。
それぞれの別名は一意であり、使用する際にはおそらく異なる名前を持ちます。</para>
<table frame="topbot" id="aliasinjection-summary">
<title>別名に挿入する名前</title>
<title>別名に挿入する名前</title>
<tgroup cols="3">
<colspec colwidth="1*" />
@ -249,60 +251,60 @@ List loggedCats = sess.createSQLQuery(sql)
<thead>
<row>
<entry>説明</entry>
<entry>構文</entry>
<entry></entry>
<entry>説明</entry>
<entry>構文</entry>
<entry></entry>
</row>
</thead>
<tbody>
<row>
<entry>単純なプロパティ</entry>
<entry>単純なプロパティ</entry>
<entry><literal>{[aliasname].[propertyname]}</literal></entry>
<entry><literal>A_NAME as {item.name}</literal></entry>
</row>
<row>
<entry>複合プロパティ</entry>
<entry>複合プロパティ</entry>
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as
{item.amount.value}</literal></entry>
</row>
<row>
<entry>エンティティのクラスを識別する値</entry>
<entry>エンティティのクラスを識別する値</entry>
<entry><literal>{[aliasname].class}</literal></entry>
<entry><literal>DISC as {item.class}</literal></entry>
</row>
<row>
<entry>エンティティの全プロパティ</entry>
<entry>エンティティの全プロパティ</entry>
<entry><literal>{[aliasname].*}</literal></entry>
<entry><literal>{item.*}</literal></entry>
</row>
<row>
<entry>コレクションのキー</entry>
<entry>コレクションのキー</entry>
<entry><literal>{[aliasname].key}</literal></entry>
<entry><literal>ORGID as {coll.key}</literal></entry>
</row>
<row>
<entry>コレクションのID</entry>
<entry>コレクションのID</entry>
<entry><literal>{[aliasname].id}</literal></entry>
<entry><literal>EMPID as {coll.id}</literal></entry>
</row>
<row>
<entry>コレクションの要素</entry>
<entry>コレクションの要素</entry>
<entry><literal>{[aliasname].element}</literal></entry>
<entry><literal>XID as {coll.element}</literal></entry>
</row>
<row>
<entry>コレクションの要素のプロパティ</entry>
<entry>コレクションの要素のプロパティ</entry>
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
<entry><literal>NAME as {coll.element.name}</literal></entry>
</row>
<row>
<entry>コレクションの要素の全プロパティ</entry>
<entry>コレクションの要素の全プロパティ</entry>
<entry><literal>{[aliasname].element.*}</literal></entry>
<entry><literal>{coll.element.*}</literal></entry>
</row>
<row>
<entry>コレクションの全プロパティ</entry>
<entry>コレクションの全プロパティ</entry>
<entry><literal>{[aliasname].*}</literal></entry>
<entry><literal>{coll.*}</literal></entry>
</row>
@ -313,43 +315,43 @@ List loggedCats = sess.createSQLQuery(sql)
</sect2>
<sect2>
<title>管理されていないエンティティの取得</title>
<title>管理されていないエンティティの取得</title>
<para>ネイティブSQLクエリに ResultTransformer を適用できます。
下記のように、例えば、管理されていないエンティティを返します。</para>
<para>ネイティブSQLクエリに ResultTransformer を適用できます。
下記のように、例えば、管理されていないエンティティを返します。</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
.setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
<para>このクエリで指定されているものを下記に示します。</para>
<para>このクエリで指定されているものを下記に示します。</para>
<itemizedlist>
<listitem>
<para>SQLクエリ文字列</para>
<para>SQLクエリ文字列</para>
</listitem>
<listitem>
<para>結果を変換したもの</para>
<para>結果を変換したもの</para>
</listitem>
</itemizedlist>
<para>上記のクエリは、インスタンス化し、NAME と BIRTHDATE の値を
対応するプロパティもしくはフィールドに挿入した <literal>CatDTO</literal>
のリストを返します。</para>
<para>上記のクエリは、インスタンス化し、NAME と BIRTHDATE の値を
対応するプロパティもしくはフィールドに挿入した <literal>CatDTO</literal>
のリストを返します。</para>
</sect2>
<sect2>
<title>継承の制御</title>
<title>継承の制御</title>
<para>継承の一部としてマッピングされたエンティティを問い合わせるネイティブSQLクエリは、
ベースのクラスとそのすべてのサブクラスのプロパティすべてを含まなければなりません。</para>
<para>継承の一部としてマッピングされたエンティティを問い合わせるネイティブSQLクエリは、
ベースのクラスとそのすべてのサブクラスのプロパティすべてを含まなければなりません。</para>
</sect2>
<sect2>
<title>パラメータ</title>
<title>パラメータ</title>
<para>ネイティブSQLクエリは、以下のように、
名前付きパラメータ(:nameと同様に位置パラメータをサポートします。</para>
<para>ネイティブSQLクエリは、以下のように、
名前付きパラメータ(:nameと同様に位置パラメータをサポートします。</para>
<programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
List pusList = query.setString(0, "Pus%").list();
@ -361,11 +363,11 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
</sect1>
<sect1 id="querysql-namedqueries" revision="3">
<title>名前付きSQLクエリ</title>
<title>名前付きSQLクエリ</title>
<para>名前付きSQLクエリはマッピングドキュメントで定義することができ、
名前付きHQLクエリと全く同じ方法で呼ぶことができます。
この場合、<literal>addEntity()</literal> を呼び出す必要は <emphasis>ない</emphasis> です。</para>
<para>名前付きSQLクエリはマッピングドキュメントで定義することができ、
名前付きHQLクエリと全く同じ方法で呼ぶことができます。
この場合、<literal>addEntity()</literal> を呼び出す必要は <emphasis>ない</emphasis> です。</para>
<programlisting><![CDATA[<sql-query name="persons">
<return alias="person" class="eg.Person"/>
@ -381,9 +383,9 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
.setMaxResults(50)
.list();]]></programlisting>
<para>関連を結合するためとコレクションを初期化するクエリを定義するために、それぞれ
<literal>&lt;return-join&gt;</literal><literal>&lt;load-collection&gt;</literal>
要素を使います。</para>
<para>関連を結合するためとコレクションを初期化するクエリを定義するために、それぞれ
<literal>&lt;return-join&gt;</literal><literal>&lt;load-collection&gt;</literal>
要素を使います。</para>
<programlisting><![CDATA[<sql-query name="personsWith">
<return alias="person" class="eg.Person"/>
@ -401,9 +403,9 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
WHERE person.NAME LIKE :namePattern
</sql-query>]]></programlisting>
<para>名前付きSQLクエリはスカラ値を返すこともできます。
<literal>&lt;return-scalar&gt;</literal> 要素を使って、
列の別名とHibernateの型を宣言しなければなりません。</para>
<para>名前付きSQLクエリはスカラ値を返すこともできます。
<literal>&lt;return-scalar&gt;</literal> 要素を使って、
列の別名とHibernateの型を宣言しなければなりません。</para>
<programlisting><![CDATA[<sql-query name="mySqlQuery">
<return-scalar column="name" type="string"/>
@ -414,10 +416,10 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
</sql-query>]]></programlisting>
<para>リザルトセットのマッピング情報を <literal>&lt;resultset&gt;</literal>
に外出しすることができます。
複数の名前付きクエリで再利用したり、<literal>setResultSetMapping()</literal>
APIを通して再利用したりできます。
<para>リザルトセットのマッピング情報を <literal>&lt;resultset&gt;</literal>
に外出しすることができます。
複数の名前付きクエリで再利用したり、<literal>setResultSetMapping()</literal>
APIを通して再利用したりできます。
</para>
<programlisting><![CDATA[<resultset name="personAddress">
@ -439,8 +441,8 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
WHERE person.NAME LIKE :namePattern
</sql-query>]]></programlisting>
<para>代わりに、hbmファイル内のリザルトセットのマッピング情報を
直接Javaコードの中で使用できます。</para>
<para>代わりに、hbmファイル内のリザルトセットのマッピング情報を
直接Javaコードの中で使用できます。</para>
<programlisting><![CDATA[List cats = sess.createSQLQuery(
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
@ -449,11 +451,11 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
.list();]]></programlisting>
<sect2 id="propertyresults">
<title>列と列の別名を明示的に指定するために return-property を使う</title>
<title>列と列の別名を明示的に指定するために return-property を使う</title>
<para>別名を挿入するために <literal>{}</literal> 構文を使う代わりに、
<literal>&lt;return-property&gt;</literal> を使い、
どの列の別名を使うのかを明示できます。</para>
<para>別名を挿入するために <literal>{}</literal> 構文を使う代わりに、
<literal>&lt;return-property&gt;</literal> を使い、
どの列の別名を使うのかを明示できます。</para>
<programlisting><![CDATA[<sql-query name="mySqlQuery">
<return alias="person" class="eg.Person">
@ -468,9 +470,9 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
</sql-query>
]]></programlisting>
<para><literal>&lt;return-property&gt;</literal> は複数の列も扱えます。
これは、複数列のプロパティをきめ細かく制御できないという、
<literal>{}</literal> 構文の制限を解決します。</para>
<para><literal>&lt;return-property&gt;</literal> は複数の列も扱えます。
これは、複数列のプロパティをきめ細かく制御できないという、
<literal>{}</literal> 構文の制限を解決します。</para>
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
<return alias="emp" class="Employment">
@ -488,24 +490,24 @@ List pusList = query.setString("name", "Pus%").list(); ]]></programlist
ORDER BY STARTDATE ASC
</sql-query>]]></programlisting>
<para>この例では、挿入のための <literal>{}</literal> 構文といっしょに、
<literal>&lt;return-property&gt;</literal> を使っていることに注意してください。
列とプロパティをどのように参照するかを選べます。</para>
<para>この例では、挿入のための <literal>{}</literal> 構文といっしょに、
<literal>&lt;return-property&gt;</literal> を使っていることに注意してください。
列とプロパティをどのように参照するかを選べます。</para>
<para>マッピングに discriminator が含まれている場合、
discriminator の列を指定するために、&lt;return-discriminator&gt;
を使わなければなりません。</para>
<para>マッピングに discriminator が含まれている場合、
discriminator の列を指定するために、&lt;return-discriminator&gt;
を使わなければなりません。</para>
</sect2>
<sect2 id="sp_query" revision="1">
<title>問い合わせするためにストアドプロシージャを使う</title>
<title>問い合わせするためにストアドプロシージャを使う</title>
<para>Hibernateはバージョン3から、ストアドプロシージャとストアド関数経由の問い合わせが
サポートされました。
以降の文書の多くは、両方に当てはまります。
ストアドプロシージャやストアド関数をHibernateで使うためには、
1番目の出力パラメータとしてリザルトセットを返さなければなりません。
Oracle 9もしくはそれ以上のバージョンのストアドプロシージャの例を以下に示します。</para>
<para>Hibernateはバージョン3から、ストアドプロシージャとストアド関数経由の問い合わせが
サポートされました。
以降の文書の多くは、両方に当てはまります。
ストアドプロシージャやストアド関数をHibernateで使うためには、
1番目の出力パラメータとしてリザルトセットを返さなければなりません。
Oracle 9もしくはそれ以上のバージョンのストアドプロシージャの例を以下に示します。</para>
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
RETURN SYS_REFCURSOR
@ -520,8 +522,8 @@ BEGIN
RETURN st_cursor;
END;]]></programlisting>
<para>Hibernateでこのクエリを使うためには、
名前付きクエリでマッピングする必要があります。</para>
<para>Hibernateでこのクエリを使うためには、
名前付きクエリでマッピングする必要があります。</para>
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
<return alias="emp" class="Employment">
@ -539,57 +541,57 @@ BEGIN
{ ? = call selectAllEmployments() }
</sql-query>]]></programlisting>
<para>注意:今のところ、ストアドプロシージャはスカラとエンティティを返すのみです。
<literal>&lt;return-join&gt;</literal><literal>&lt;load-collection&gt;</literal>
はサポートされていません。</para>
<para>注意:今のところ、ストアドプロシージャはスカラとエンティティを返すのみです。
<literal>&lt;return-join&gt;</literal><literal>&lt;load-collection&gt;</literal>
はサポートされていません。</para>
<sect3 id="querysql-limits-storedprocedures" revision="1">
<title>ストアドプロシージャを使う上でのルールと制限</title>
<title>ストアドプロシージャを使う上でのルールと制限</title>
<para>Hibernateでストアドプロシージャや関数を使うためには、
そのプロシージャはいくつかのルールに準拠する必要があります。
ルールに準拠していないプロシージャは、Hibernateで使うことはできません。
それでも、準拠していないプロシージャを使いたいのであれば、
<literal>session.connection()</literal> を通じて実行しなければなりません。
ルールはデータベースごとに異なります。
ストアドプロシージャのセマンティックスとシンタックスは、
データベースベンダごとに異なるためです。</para>
<para>Hibernateでストアドプロシージャや関数を使うためには、
そのプロシージャはいくつかのルールに準拠する必要があります。
ルールに準拠していないプロシージャは、Hibernateで使うことはできません。
それでも、準拠していないプロシージャを使いたいのであれば、
<literal>session.connection()</literal> を通じて実行しなければなりません。
ルールはデータベースごとに異なります。
ストアドプロシージャのセマンティックスとシンタックスは、
データベースベンダごとに異なるためです。</para>
<para><literal>setFirstResult()/setMaxResults()</literal> を使って、
ストアドプロシージャクエリをページ分けすることはできません。</para>
<para><literal>setFirstResult()/setMaxResults()</literal> を使って、
ストアドプロシージャクエリをページ分けすることはできません。</para>
<para>推奨する呼び出し方は、標準であるSQL92に従うことです。
<literal>{ ? = call functionName(&lt;parameters&gt;) }</literal>
<literal>{ ? = call procedureName(&lt;parameters&gt;) }</literal> です。
ネイティブな呼び出し構文はサポートされていません。</para>
<para>推奨する呼び出し方は、標準であるSQL92に従うことです。
<literal>{ ? = call functionName(&lt;parameters&gt;) }</literal>
<literal>{ ? = call procedureName(&lt;parameters&gt;) }</literal> です。
ネイティブな呼び出し構文はサポートされていません。</para>
<para>Oracleには下記のルールが適用されます。</para>
<para>Oracleには下記のルールが適用されます。</para>
<itemizedlist spacing="compact">
<listitem>
<para>関数はリザルトセットを返さなければなりません。
プロシージャの第一引数はリザルトセットを返すため、
<literal>OUT</literal> でなければなりません。
Oracle 9と10では、<literal>SYS_REFCURSOR</literal> を使うことによってできます。
Oracleでは <literal>REF CURSOR</literal> 型を定義する必要があります。
Oracleの文献を参照してください。</para>
<para>関数はリザルトセットを返さなければなりません。
プロシージャの第一引数はリザルトセットを返すため、
<literal>OUT</literal> でなければなりません。
Oracle 9と10では、<literal>SYS_REFCURSOR</literal> を使うことによってできます。
Oracleでは <literal>REF CURSOR</literal> 型を定義する必要があります。
Oracleの文献を参照してください。</para>
</listitem>
</itemizedlist>
<para>SybaseとMS SQLサーバーに適用されるルールを下記に示します。</para>
<para>SybaseとMS SQLサーバーに適用されるルールを下記に示します。</para>
<itemizedlist spacing="compact">
<listitem>
<para>プロシージャはリザルトセットを返さなければなりません。
サーバーは複数のリザルトセットと更新カウントを返しますが、
Hibernateは1つ目のリザルトセットだけを返すことに注意してください。
その他はすべて捨てられます。</para>
<para>プロシージャはリザルトセットを返さなければなりません。
サーバーは複数のリザルトセットと更新カウントを返しますが、
Hibernateは1つ目のリザルトセットだけを返すことに注意してください。
その他はすべて捨てられます。</para>
</listitem>
<listitem>
<para>プロシージャの中で <literal>SET NOCOUNT ON</literal> を有効にできれば、
おそらく効率がよくなるでしょう。
しかし、これは必要条件ではありません。</para>
<para>プロシージャの中で <literal>SET NOCOUNT ON</literal> を有効にできれば、
おそらく効率がよくなるでしょう。
しかし、これは必要条件ではありません。</para>
</listitem>
</itemizedlist>
</sect3>
@ -597,15 +599,15 @@ BEGIN
</sect1>
<sect1 id="querysql-cud">
<title>作成、更新、削除のためのカスタムSQL</title>
<title>作成、更新、削除のためのカスタムSQL</title>
<para>Hibernate3は作成、更新、削除処理のためのカスタムSQL文を使用できます。
クラスとコレクションの永続化機構は、コンフィグレーション時に生成された文字列
insertsql、deletesql、updatesqlなどのセットをすでに保持しています。
これらの文字列より、
<literal>&lt;sql-insert&gt;</literal>
<literal>&lt;sql-delete&gt;</literal>
<literal>&lt;sql-update&gt;</literal> というマッピングタグが優先されます。</para>
<para>Hibernate3は作成、更新、削除処理のためのカスタムSQL文を使用できます。
クラスとコレクションの永続化機構は、コンフィグレーション時に生成された文字列
insertsql、deletesql、updatesqlなどのセットをすでに保持しています。
これらの文字列より、
<literal>&lt;sql-insert&gt;</literal>
<literal>&lt;sql-delete&gt;</literal>
<literal>&lt;sql-update&gt;</literal> というマッピングタグが優先されます。</para>
<programlisting><![CDATA[<class name="Person">
<id name="id">
@ -617,11 +619,11 @@ BEGIN
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
</class>]]></programlisting>
<para>SQLを直接データベースで実行するため、好みの方言を自由に使用できます。
データベース独自のSQLを使えば、当然マッピングのポータビリティが下がります。</para>
<para>SQLを直接データベースで実行するため、好みの方言を自由に使用できます。
データベース独自のSQLを使えば、当然マッピングのポータビリティが下がります。</para>
<para><literal>callable</literal> 属性をセットすれば、
ストアドプロシージャを使用できます。</para>
<para><literal>callable</literal> 属性をセットすれば、
ストアドプロシージャを使用できます。</para>
<programlisting><![CDATA[<class name="Person">
<id name="id">
@ -633,21 +635,21 @@ BEGIN
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
</class>]]></programlisting>
<para>今のところ、位置パラメータの順番はとても重要です。
すなわち、Hibernateが期待する順序でなければなりません。</para>
<para>今のところ、位置パラメータの順番はとても重要です。
すなわち、Hibernateが期待する順序でなければなりません。</para>
<para><literal>org.hiberante.persister.entity</literal> レベルのデバッグログを
有効にすることによって、期待される順番を確かめられます。
このレベルを有効にすることにより、エンティティの作成、更新、削除などで
使用される静的なSQLが出力されます。
期待される順序を確認するためには、Hibernateが生成する静的なSQLをオーバーライドする
カスタムSQLをマッピングファイルに含めないことを忘れないでください。</para>
<para><literal>org.hiberante.persister.entity</literal> レベルのデバッグログを
有効にすることによって、期待される順番を確かめられます。
このレベルを有効にすることにより、エンティティの作成、更新、削除などで
使用される静的なSQLが出力されます。
期待される順序を確認するためには、Hibernateが生成する静的なSQLをオーバーライドする
カスタムSQLをマッピングファイルに含めないことを忘れないでください。</para>
<para>ストアドプロシージャは挿入/更新/削除された行数を返す必要があります
(読み込みの場合は、返さないよりは返す方がよいです)。
実行時にHibernateがSQL文の成功をチェックするからです。
Hibernateは、CUD処理のための数値の出力パラメータとして、
SQL文の最初のパラメータをいつも記録します。</para>
<para>ストアドプロシージャは挿入/更新/削除された行数を返す必要があります
(読み込みの場合は、返さないよりは返す方がよいです)。
実行時にHibernateがSQL文の成功をチェックするからです。
Hibernateは、CUD処理のための数値の出力パラメータとして、
SQL文の最初のパラメータをいつも記録します。</para>
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
RETURN NUMBER IS
@ -665,9 +667,9 @@ END updatePerson;]]></programlisting>
</sect1>
<sect1 id="querysql-load">
<title>ロードのためのカスタムSQL</title>
<title>ロードのためのカスタムSQL</title>
<para>エンティティを読み込むための独自のSQLもしくはHQLクエリも宣言できます。</para>
<para>エンティティを読み込むための独自のSQLもしくはHQLクエリも宣言できます。</para>
<programlisting><![CDATA[<sql-query name="person">
<return alias="pers" class="Person" lock-mode="upgrade"/>
@ -677,8 +679,8 @@ END updatePerson;]]></programlisting>
FOR UPDATE
</sql-query>]]></programlisting>
<para>これは、まさに(以前議論した)名前付きクエリの宣言です。
この名前付きクエリをクラスのマッピングから参照できます。</para>
<para>これは、まさに(以前議論した)名前付きクエリの宣言です。
この名前付きクエリをクラスのマッピングから参照できます。</para>
<programlisting><![CDATA[<class name="Person">
<id name="id">
@ -689,9 +691,9 @@ END updatePerson;]]></programlisting>
</class>]]></programlisting>
<para>これはストアドプロシージャでさえも動作します。</para>
<para>これはストアドプロシージャでさえも動作します。</para>
<para>次のように、コレクションをロードするためのクエリさえ定義してよいです。</para>
<para>次のように、コレクションをロードするためのクエリさえ定義してよいです。</para>
<programlisting><![CDATA[<set name="employments" inverse="true">
<key/>
@ -707,8 +709,8 @@ END updatePerson;]]></programlisting>
ORDER BY STARTDATE ASC, EMPLOYEE ASC
</sql-query>]]></programlisting>
<para>次のように、結合フェッチによりコレクションをロードする
エンティティローダーを定義できます。</para>
<para>次のように、結合フェッチによりコレクションをロードする
エンティティローダーを定義できます。</para>
<programlisting><![CDATA[<sql-query name="person">
<return alias="pers" class="Person"/>
@ -721,4 +723,4 @@ END updatePerson;]]></programlisting>
</sql-query>]]></programlisting>
</sect1>
</chapter>
</chapter>

View File

@ -1,39 +1,41 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="toolsetguide" revision="2">
<title>Toolset Guide
ツールセットガイド
ツールセットガイド
</title>
<para>
Hibernateを使ったラウンドトリップエンジニアリングは、
Eclipseプラグインやコマンドラインツール、もちろんAntタスクを使うことで可能です。
Hibernateを使ったラウンドトリップエンジニアリングは、
Eclipseプラグインやコマンドラインツール、もちろんAntタスクを使うことで可能です。
</para>
<para>
<emphasis>Hibernate Tools</emphasis> は現在、既存データベースのリバースエンジニアリングのAntタスクに加えて、EclipseIDEのプラグインを含みます。
<emphasis>Hibernate Tools</emphasis> は現在、既存データベースのリバースエンジニアリングのAntタスクに加えて、EclipseIDEのプラグインを含みます。
</para>
<itemizedlist>
<listitem><para>
<emphasis>マッピングエディタ:</emphasis>
HibernateのXMLマッピングファイル用のエディタで、
自動補完と構文強調表示をサポートしています。クラス名やプロパティ/フィールド名に対する自動補完もサポートし、
通常のXMLエディタよりも強力です。
<emphasis>マッピングエディタ:</emphasis>
HibernateのXMLマッピングファイル用のエディタで、
自動補完と構文強調表示をサポートしています。クラス名やプロパティ/フィールド名に対する自動補完もサポートし、
通常のXMLエディタよりも強力です。
</para></listitem>
<listitem><para>
<emphasis>Console:</emphasis>
コンソールはエクリプスの新しいビューです。
コンソールコンフィギュレーションのツリーオーバービューに加えて、永続クラスとその関連の相互作用ビューも得られます。
データベースにHQLを実行し、結果を直接エクリプス上で見ることができます。
コンソールはエクリプスの新しいビューです。
コンソールコンフィギュレーションのツリーオーバービューに加えて、永続クラスとその関連の相互作用ビューも得られます。
データベースにHQLを実行し、結果を直接エクリプス上で見ることができます。
</para></listitem>
<listitem><para>
<emphasis>開発ウィザード</emphasis>
HibernateのEclipseツールはいくつかのウィザードを提供します。
ウィザードを使ってHibernateの設定ファイル(cfg.xml)をすばやく生成したり、
既存のデータベーススキーマをPOJOのソースファイルとHibernateのマッピングファイルへと、
完全にリバースエンジニアリングすることができます。
リバースエンジニアリングウィザードはカスタマイズ可能なテンプレートをサポートします。
<emphasis>開発ウィザード</emphasis>
HibernateのEclipseツールはいくつかのウィザードを提供します。
ウィザードを使ってHibernateの設定ファイル(cfg.xml)をすばやく生成したり、
既存のデータベーススキーマをPOJOのソースファイルとHibernateのマッピングファイルへと、
完全にリバースエンジニアリングすることができます。
リバースエンジニアリングウィザードはカスタマイズ可能なテンプレートをサポートします。
</para></listitem>
<listitem><para>
<emphasis>Ant Tasks:</emphasis>
@ -42,43 +44,43 @@
</itemizedlist>
<para>
より詳しい情報は <emphasis>Hibernate Tools</emphasis> パッケージとそのドキュメントを参照してください。
より詳しい情報は <emphasis>Hibernate Tools</emphasis> パッケージとそのドキュメントを参照してください。
</para>
<para>
しかし、Hibernateのメインパッケージは <emphasis>SchemaExport</emphasis>
別名 <literal>hbm2ddl</literal> も含みます(Hibernate内でオンザフライで使用できます)。
しかし、Hibernateのメインパッケージは <emphasis>SchemaExport</emphasis>
別名 <literal>hbm2ddl</literal> も含みます(Hibernate内でオンザフライで使用できます)。
</para>
<sect1 id="toolsetguide-s1" revision="2">
<title>スキーマの自動生成</title>
<title>スキーマの自動生成</title>
<para>
DDLはHibernateユーティリティによりマッピングファイルから生成することができます。
生成されたスキーマはエンティティやコレクションのテーブルに対する参照整合性制約(主キーと外部キー)を含みます。
テーブルとシーケンスはマッピングする識別子ジェネレータに対して生成されます。
DDLはHibernateユーティリティによりマッピングファイルから生成することができます。
生成されたスキーマはエンティティやコレクションのテーブルに対する参照整合性制約(主キーと外部キー)を含みます。
テーブルとシーケンスはマッピングする識別子ジェネレータに対して生成されます。
</para>
<para>
DDLはベンダー依存なので、このツールを使うときは、<literal>hibernate.dialect</literal>
プロパティでSQLの <literal>方言</literal> を指定 <emphasis>しなければなりません</emphasis>
DDLはベンダー依存なので、このツールを使うときは、<literal>hibernate.dialect</literal>
プロパティでSQLの <literal>方言</literal> を指定 <emphasis>しなければなりません</emphasis>
</para>
<para>
まず、生成されるスキーマを改善するように、マッピングファイルをカスタマイズしてください。
まず、生成されるスキーマを改善するように、マッピングファイルをカスタマイズしてください。
</para>
<sect2 id="toolsetguide-s1-2" revision="3">
<title>スキーマのカスタマイズ</title>
<title>スキーマのカスタマイズ</title>
<para>
多くのHibernateのマッピング要素では、オプションの <literal>length</literal> という名の属性を定義しています。
この属性でカラム長を設定することができます(またはNUMERIC/DECIMAL型のデータの精度を設定できます)。
多くのHibernateのマッピング要素では、オプションの <literal>length</literal> という名の属性を定義しています。
この属性でカラム長を設定することができます(またはNUMERIC/DECIMAL型のデータの精度を設定できます)。
</para>
<para>
<literal>not-null</literal> 属性(テーブルのカラムへ <literal>NOT NULL</literal> 制約を生成する)と
<literal>unique</literal> 属性(テーブルのカラムへ <literal>UNIQUE</literal> 制約を生成する)が設定できるタグもあります。
<literal>not-null</literal> 属性(テーブルのカラムへ <literal>NOT NULL</literal> 制約を生成する)と
<literal>unique</literal> 属性(テーブルのカラムへ <literal>UNIQUE</literal> 制約を生成する)が設定できるタグもあります。
</para>
<programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
@ -86,9 +88,9 @@
<programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
<para>
<literal>unique-key</literal> 属性はカラムをグループ化して一つのキー制約にするために使われます。
現在、<literal>unique-key</literal> 属性で指定された値は制約の指定には <emphasis>使われず</emphasis>
マッピングファイルでカラムをグループ化することにのみ使われます。
<literal>unique-key</literal> 属性はカラムをグループ化して一つのキー制約にするために使われます。
現在、<literal>unique-key</literal> 属性で指定された値は制約の指定には <emphasis>使われず</emphasis>
マッピングファイルでカラムをグループ化することにのみ使われます。
</para>
<programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
@ -97,21 +99,21 @@
<para>
<literal>index</literal> 属性はマッピングするカラムを使って生成したインデックスの名前を指定します。
複数カラムを1つのインデックスにグループ化できます。単に、同じインデックス名を指定するだけです。
<literal>index</literal> 属性はマッピングするカラムを使って生成したインデックスの名前を指定します。
複数カラムを1つのインデックスにグループ化できます。単に、同じインデックス名を指定するだけです。
</para>
<programlisting><![CDATA[<property name="lastName" index="CustName"/>
<property name="firstName" index="CustName"/>]]></programlisting>
<para>
<literal>foreign-key</literal> 属性は、生成された外部キー制約の名前をオーバーライドするために使用できます。
<literal>foreign-key</literal> 属性は、生成された外部キー制約の名前をオーバーライドするために使用できます。
</para>
<programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
<para>
多くのマッピング要素は、子 <literal>&lt;column&gt;</literal> 要素を記述できます。これは複数カラム型のマッピングには特に有用です。
多くのマッピング要素は、子 <literal>&lt;column&gt;</literal> 要素を記述できます。これは複数カラム型のマッピングには特に有用です。
</para>
<programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
@ -121,9 +123,9 @@
</property>]]></programlisting>
<para>
<literal>default</literal> 属性はカラムのデフォルト値を指定します
(マッピングしたクラスの新しいインスタンスを保存する前に、
マッピングしたプロパティへ同じ値を代入すべきです)。
<literal>default</literal> 属性はカラムのデフォルト値を指定します
(マッピングしたクラスの新しいインスタンスを保存する前に、
マッピングしたプロパティへ同じ値を代入すべきです)。
</para>
<programlisting><![CDATA[<property name="credits" type="integer" insert="false">
@ -135,7 +137,7 @@
</property>]]></programlisting>
<para>
<literal>sql-type</literal> 属性で、デフォルトのHibernate型からSQLのデータ型へのマッピングをオーバーライドできます。
<literal>sql-type</literal> 属性で、デフォルトのHibernate型からSQLのデータ型へのマッピングをオーバーライドできます。
</para>
@ -145,7 +147,7 @@
<para>
<literal>check</literal> 属性でチェック制約を指定することができます。
<literal>check</literal> 属性でチェック制約を指定することができます。
</para>
<programlisting><![CDATA[<property name="foo" type="integer">
@ -159,94 +161,94 @@
<table frame="topbot" id="schemattributes-summary" revision="2">
<title>まとめ</title>
<title>まとめ</title>
<tgroup cols="3">
<colspec colwidth="1*"/>
<colspec colwidth="1*"/>
<colspec colwidth="2.5*"/>
<thead>
<row>
<entry>属性</entry>
<entry></entry>
<entry>説明</entry>
<entry>属性</entry>
<entry></entry>
<entry>説明</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>length</literal></entry>
<entry>数値</entry>
<entry>カラムの長さ</entry>
<entry>数値</entry>
<entry>カラムの長さ</entry>
</row>
<row>
<entry><literal>precision</literal></entry>
<entry>数値</entry>
<entry>カラムのDECIMAL型の精度precision</entry>
<entry>数値</entry>
<entry>カラムのDECIMAL型の精度precision</entry>
</row>
<row>
<entry><literal>scale</literal></entry>
<entry>数値</entry>
<entry>カラムのDECIMAL型のスケールscale</entry>
<entry>数値</entry>
<entry>カラムのDECIMAL型のスケールscale</entry>
</row>
<row>
<entry><literal>not-null</literal></entry>
<entry><literal>true|false</literal></entry>
<entry>カラムがnull値を取らないことを指定します
<entry>カラムがnull値を取らないことを指定します
</entry>
</row>
<row>
<entry><literal>unique</literal></entry>
<entry><literal>true|false</literal></entry>
<entry>カラムがユニーク制約を持つことを指定します
<entry>カラムがユニーク制約を持つことを指定します
</entry>
</row>
<row>
<entry><literal>index</literal></entry>
<entry><literal>インデックス名</literal> </entry>
<entry>(複数カラムの)インデックスの名前を指定します
<entry><literal>インデックス名</literal> </entry>
<entry>(複数カラムの)インデックスの名前を指定します
</entry>
</row>
<row>
<entry><literal>unique-key</literal></entry>
<entry><literal>ユニークキー名</literal></entry>
<entry>複数カラムのユニーク制約の名前を指定します
<entry><literal>ユニークキー名</literal></entry>
<entry>複数カラムのユニーク制約の名前を指定します
</entry>
</row>
<row>
<entry><literal>foreign-key</literal></entry>
<entry><literal>外部キー名</literal></entry>
<entry><literal>外部キー名</literal></entry>
<entry>
&lt;one-to-one&gt;&lt;many-to-one&gt;&lt;many-to-many&gt;マッピング要素を使って、
関連に対し生成された外部キー制約の名前を指定します。
<literal>SchemaExport</literal><literal>inverse="true"</literal> 側を考慮しないことに注意してください。
&lt;one-to-one&gt;&lt;many-to-one&gt;&lt;many-to-many&gt;マッピング要素を使って、
関連に対し生成された外部キー制約の名前を指定します。
<literal>SchemaExport</literal><literal>inverse="true"</literal> 側を考慮しないことに注意してください。
</entry>
</row>
<row>
<entry><literal>sql-type</literal></entry>
<entry><literal>SQLのカラム型</literal></entry>
<entry><literal>SQLのカラム型</literal></entry>
<entry>
デフォルトのカラム型をオーバーライドします( <literal>&lt;column&gt;</literal> 要素の属性のみ)
デフォルトのカラム型をオーバーライドします( <literal>&lt;column&gt;</literal> 要素の属性のみ)
</entry>
</row>
<row>
<entry><literal>default</literal></entry>
<entry>SQL式</entry>
<entry>SQL式</entry>
<entry>
カラムのデフォルト値を指定します
カラムのデフォルト値を指定します
</entry>
</row>
<row>
<entry><literal>check</literal></entry>
<entry>SQL式</entry>
<entry>SQL式</entry>
<entry>
カラムかテーブルにSQLのチェック制約を作成します
カラムかテーブルにSQLのチェック制約を作成します
</entry>
</row>
</tbody>
@ -254,7 +256,7 @@
</table>
<para>
<literal>&lt;comment&gt;</literal> 要素で生成するスキーマにコメントを指定することができます。
<literal>&lt;comment&gt;</literal> 要素で生成するスキーマにコメントを指定することができます。
</para>
@ -270,16 +272,16 @@
</property>]]></programlisting>
<para>
これにより、生成したDDLに <literal>comment on table</literal><literal>comment on column</literal> 文が書かれます。
これにより、生成したDDLに <literal>comment on table</literal><literal>comment on column</literal> 文が書かれます。
</para>
</sect2>
<sect2 id="toolsetguide-s1-3" revision="2">
<title>ツールの実行</title>
<title>ツールの実行</title>
<para>
<literal>SchemaExport</literal> は標準出力に対してDDLスクリプトを書き出し、DDL文を実行したりもします。
<literal>SchemaExport</literal> は標準出力に対してDDLスクリプトを書き出し、DDL文を実行したりもします。
</para>
<para>
@ -290,70 +292,70 @@
<table frame="topbot">
<title> <literal>SchemaExport</literal> Command Line Options
<literal>SchemaExport</literal> のコマンドラインオプション
<literal>SchemaExport</literal> のコマンドラインオプション
</title>
<tgroup cols="2">
<colspec colwidth="1.5*"/>
<colspec colwidth="2*"/>
<thead>
<row>
<entry>オプション</entry>
<entry>説明</entry>
<entry>オプション</entry>
<entry>説明</entry>
</row>
</thead>
<tbody>
<row>
<entry> <literal>--quiet</literal> </entry>
<entry>スクリプトを標準出力に出力しません</entry>
<entry>スクリプトを標準出力に出力しません</entry>
</row>
<row>
<entry> <literal>--drop</literal> </entry>
<entry>テーブルの削除だけを行います</entry>
<entry>テーブルの削除だけを行います</entry>
</row>
<row>
<entry> <literal>--create</literal> </entry>
<entry>テーブルの生成のみを行います。
<entry>テーブルの生成のみを行います。
</entry>
</row>
<row>
<entry> <literal>--text</literal> </entry>
<entry>データベースにエクスポートしません</entry>
<entry>データベースにエクスポートしません</entry>
</row>
<row>
<entry> <literal>--output=my_schema.ddl</literal> </entry>
<entry> DDLスクリプトをファイルに出力します</entry>
<entry> DDLスクリプトをファイルに出力します</entry>
</row>
<row>
<entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
<entry> <literal>NamingStrategy</literal> を選択します
<entry> <literal>NamingStrategy</literal> を選択します
</entry>
</row>
<row>
<entry><literal>--config=hibernate.cfg.xml</literal> </entry>
<entry>XMLファイルからHibernateの定義情報を読み込みます</entry>
<entry>XMLファイルからHibernateの定義情報を読み込みます</entry>
</row>
<row>
<entry> <literal>--properties=hibernate.properties</literal> </entry>
<entry>ファイルからデータベースプロパティを読み込みます</entry>
<entry>ファイルからデータベースプロパティを読み込みます</entry>
</row>
<row>
<entry> <literal>--format</literal> </entry>
<entry>スクリプト内に生成するSQLを読みやすいようにフォーマットします</entry>
<entry>スクリプト内に生成するSQLを読みやすいようにフォーマットします</entry>
</row>
<row>
<entry> <literal>--delimiter=x</literal> </entry>
<entry>スクリプトの行区切り文字を設定します</entry>
<entry>スクリプトの行区切り文字を設定します</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
アプリケーションに <literal>SchemaExport</literal> を組み込むこともできます:
アプリケーションに <literal>SchemaExport</literal> を組み込むこともできます:
</para>
<programlisting><![CDATA[Configuration cfg = ....;
@ -363,69 +365,69 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
<sect2 id="toolsetguide-s1-4">
<title>プロパティ</title>
<title>プロパティ</title>
<para>
次のように、データベースのプロパティを指定することができます。
次のように、データベースのプロパティを指定することができます。
</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>-D</literal> <emphasis>&lt;property&gt;</emphasis> を使って、システムプロパティとして
<para><literal>-D</literal> <emphasis>&lt;property&gt;</emphasis> を使って、システムプロパティとして
</para>
</listitem>
<listitem>
<para><literal>hibernate.properties</literal> ファイル内で
<para><literal>hibernate.properties</literal> ファイル内で
</para>
</listitem>
<listitem>
<para> <literal>--properties</literal> を使って指定したプロパティファイル内で
<para> <literal>--properties</literal> を使って指定したプロパティファイル内で
</para>
</listitem>
</itemizedlist>
<para>
必要なプロパティは以下のものです:
必要なプロパティは以下のものです:
</para>
<table frame="topbot">
<title>SchemaExportコネクションプロパティ</title>
<title>SchemaExportコネクションプロパティ</title>
<tgroup cols="2">
<colspec colwidth="1.5*"/>
<colspec colwidth="2*"/>
<thead>
<row>
<entry>プロパティ名
<entry>プロパティ名
</entry>
<entry>説明
<entry>説明
</entry>
</row>
</thead>
<tbody>
<row>
<entry> <literal>hibernate.connection.driver_class</literal> </entry>
<entry>jdbcのドライバークラス
<entry>jdbcのドライバークラス
</entry>
</row>
<row>
<entry> <literal>hibernate.connection.url</literal> </entry>
<entry>jdbcのurl
<entry>jdbcのurl
</entry>
</row>
<row>
<entry> <literal>hibernate.connection.username</literal> </entry>
<entry>データベースのユーザ
<entry>データベースのユーザ
</entry>
</row>
<row>
<entry> <literal>hibernate.connection.password</literal> </entry>
<entry>ユーザパスワード
<entry>ユーザパスワード
</entry>
</row>
<row>
<entry> <literal>hibernate.dialect</literal> </entry>
<entry>データベース方言
<entry>データベース方言
</entry>
</row>
</tbody>
@ -435,10 +437,10 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
</sect2>
<sect2 id="toolsetguide-s1-5">
<title>Antを使用する</title>
<title>Antを使用する</title>
<para>
Antのビルドスクリプトから <literal>SchemaExport</literal> を呼び出すことができます。:
Antのビルドスクリプトから <literal>SchemaExport</literal> を呼び出すことができます。:
</para>
<programlisting><![CDATA[<target name="schemaexport">
@ -462,13 +464,13 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
</sect2>
<sect2 id="toolsetguide-s1-6" revision="2">
<title>インクリメンタルなスキーマ更新
<title>インクリメンタルなスキーマ更新
</title>
<para>
<literal>SchemaUpdate</literal> ツールは既存のスキーマをインクリメンタルに更新します。
<literal>SchemaUpdate</literal> はJDBCのメタデータAPIに強く依存します。
そのため、すべてのJDBCドライバでうまくいくとは限らないことに注意してください。
<literal>SchemaUpdate</literal> ツールは既存のスキーマをインクリメンタルに更新します。
<literal>SchemaUpdate</literal> はJDBCのメタデータAPIに強く依存します。
そのため、すべてのJDBCドライバでうまくいくとは限らないことに注意してください。
</para>
<para>
@ -477,42 +479,42 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
</para>
<table frame="topbot">
<title> <literal>SchemaUpdate</literal> のコマンドライン・オプション</title>
<title> <literal>SchemaUpdate</literal> のコマンドライン・オプション</title>
<tgroup cols="2">
<colspec colwidth="1.5*"/>
<colspec colwidth="2*"/>
<thead>
<row>
<entry>オプション</entry>
<entry>説明</entry>
<entry>オプション</entry>
<entry>説明</entry>
</row>
</thead>
<tbody>
<row>
<entry> <literal>--quiet</literal> </entry>
<entry>標準出力にスクリプトを出力しません</entry>
<entry>標準出力にスクリプトを出力しません</entry>
</row>
<row>
<entry> <literal>--text</literal> </entry>
<entry>データベースにスクリプトをエクスポートしません
<entry>データベースにスクリプトをエクスポートしません
</entry>
</row>
<row>
<entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
<entry><literal>NamingStrategy</literal> を選択します。
<entry><literal>NamingStrategy</literal> を選択します。
</entry>
</row>
<row>
<entry> <literal>--properties=hibernate.properties</literal> </entry>
<entry>ファイルからデータベースプロパティを読み込みます
<entry>ファイルからデータベースプロパティを読み込みます
</entry>
</row>
<row>
<entry> <literal>--config=hibernate.cfg.xml</literal> </entry>
<entry><literal>.cfg.xml</literal> ファイルを指定します
<entry><literal>.cfg.xml</literal> ファイルを指定します
</entry>
</row>
@ -521,7 +523,7 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
</table>
<para>
アプリケーションに <literal>SchemaUpdate</literal> を組み込むことができます。:
アプリケーションに <literal>SchemaUpdate</literal> を組み込むことができます。:
</para>
<programlisting><![CDATA[Configuration cfg = ....;
@ -531,10 +533,10 @@ new SchemaUpdate(cfg).execute(false);]]></programlisting>
<sect2 id="toolsetguide-s1-7">
<title>インクリメンタルなスキーマ更新に対するAntの使用</title>
<title>インクリメンタルなスキーマ更新に対するAntの使用</title>
<para>
Antスクリプトから <literal>SchemaUpdate</literal> を呼び出すことができます:
Antスクリプトから <literal>SchemaUpdate</literal> を呼び出すことができます:
</para>
<programlisting><![CDATA[<target name="schemaupdate">
@ -557,7 +559,7 @@ new SchemaUpdate(cfg).execute(false);]]></programlisting>
<title>Schema validation</title>
<para>
<literal>SchemaValidator</literal> ツールは、既存のデータベーススキーマと作成したマッピングドキュメントが"一致する"ことを検証します。 <literal>SchemaValidator</literal> はJDBCのメタデータAPIに強く依存することに注意してください。そのため、すべてのJDBCドライバーで作動するものではありません。このツールはテスト時に非常に有用です。
<literal>SchemaValidator</literal> ツールは、既存のデータベーススキーマと作成したマッピングドキュメントが"一致する"ことを検証します。 <literal>SchemaValidator</literal> はJDBCのメタデータAPIに強く依存することに注意してください。そのため、すべてのJDBCドライバーで作動するものではありません。このツールはテスト時に非常に有用です。
</para>
<para>
@ -566,31 +568,31 @@ new SchemaUpdate(cfg).execute(false);]]></programlisting>
</para>
<table frame="topbot">
<title> <literal>SchemaValidator</literal> のコマンドライン・オプション
<title> <literal>SchemaValidator</literal> のコマンドライン・オプション
</title>
<tgroup cols="2">
<colspec colwidth="1.5*"/>
<colspec colwidth="2*"/>
<thead>
<row>
<entry>オプション</entry>
<entry>説明</entry>
<entry>オプション</entry>
<entry>説明</entry>
</row>
</thead>
<tbody>
<row>
<entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
<entry><literal>NamingStrategy</literal> を選択します
<entry><literal>NamingStrategy</literal> を選択します
</entry>
</row>
<row>
<entry> <literal>--properties=hibernate.properties</literal> </entry>
<entry>ファイルからデータベースのプロパティを読み込みます
<entry>ファイルからデータベースのプロパティを読み込みます
</entry>
</row>
<row>
<entry> <literal>--config=hibernate.cfg.xml</literal> </entry>
<entry><literal>.cfg.xml</literal> ファイルを指定します
<entry><literal>.cfg.xml</literal> ファイルを指定します
</entry>
</row>
</tbody>
@ -598,7 +600,7 @@ new SchemaUpdate(cfg).execute(false);]]></programlisting>
</table>
<para>
<literal>SchemaValidator</literal> をアプリケーションに組み込むことが出来ます:
<literal>SchemaValidator</literal> をアプリケーションに組み込むことが出来ます:
</para>
<programlisting><![CDATA[Configuration cfg = ....;
@ -607,10 +609,10 @@ new SchemaValidator(cfg).validate();]]></programlisting>
</sect2>
<sect2 id="toolsetguide-s1-9">
<title>スキーマのバリデーションにAntを使用します</title>
<title>スキーマのバリデーションにAntを使用します</title>
<para>
Antスクリプトから <literal>SchemaValidator</literal> を呼び出せます:
Antスクリプトから <literal>SchemaValidator</literal> を呼び出せます:
</para>
<programlisting><![CDATA[<target name="schemavalidate">

View File

@ -1,48 +1,50 @@
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="xml">
<title>XMLマッピング</title>
<title>XMLマッピング</title>
<para><emphasis>XMLマッピングはHibernate3.0では試験的な機能であり、非常に活動的に開発中です。</emphasis></para>
<para><emphasis>XMLマッピングはHibernate3.0では試験的な機能であり、非常に活動的に開発中です。</emphasis></para>
<sect1 id="xml-intro" revision="1">
<title>XMLデータでの作業</title>
<title>XMLデータでの作業</title>
<para>
Hibernateでは永続性のPOJOを使って作業するのとほぼ同じようなやり方で、
永続性のXMLデータを使って作業できます。
Hibernateでは永続性のPOJOを使って作業するのとほぼ同じようなやり方で、
永続性のXMLデータを使って作業できます。
</para>
<para>
HibernateはXMLツリーを操作するためのAPIとしてdom4jをサポートしています。
データベースからdom4jのツリーを復元するクエリを書くことができ、
ツリーに対して行った修正は自動的にデータベースと同期されます。
HibernateはXMLツリーを操作するためのAPIとしてdom4jをサポートしています。
データベースからdom4jのツリーを復元するクエリを書くことができ、
ツリーに対して行った修正は自動的にデータベースと同期されます。
またXMLドキュメントを取得することができ、dom4jを使ってドキュメントをパースし、
Hibernateの任意の基本操作を使ってデータベースへ書き込むことができます。
つまり、<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
操作です(マージはまだサポートしていません)。
またXMLドキュメントを取得することができ、dom4jを使ってドキュメントをパースし、
Hibernateの任意の基本操作を使ってデータベースへ書き込むことができます。
つまり、<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
操作です(マージはまだサポートしていません)。
</para>
<para>
データのインポート/エクスポート、
JMSによるエンティティデータの外部化やSOAP、XSLTベースのレポートなど、
この機能には多くの用途があります。
データのインポート/エクスポート、
JMSによるエンティティデータの外部化やSOAP、XSLTベースのレポートなど、
この機能には多くの用途があります。
</para>
<para>
単一のマッピングは、クラスのプロパティとXMLドキュメントのードを
同時にデータベースへマッピングするために使うことができます。
またマッピングするクラスがなければ、
XMLだけをマッピングするために使うことができます。
単一のマッピングは、クラスのプロパティとXMLドキュメントのードを
同時にデータベースへマッピングするために使うことができます。
またマッピングするクラスがなければ、
XMLだけをマッピングするために使うことができます。
</para>
<sect2 id="xml-intro-mapping">
<title>XMLとクラスのマッピングを同時に指定する</title>
<title>XMLとクラスのマッピングを同時に指定する</title>
<para>
これはPOJOとXMLを同時にマッピングする例です。
これはPOJOとXMLを同時にマッピングする例です。
</para>
<programlisting><![CDATA[<class name="Account"
@ -68,10 +70,10 @@
</sect2>
<sect2 id="xml-onlyxml">
<title>XMLマッピングだけを指定する</title>
<title>XMLマッピングだけを指定する</title>
<para>
これはPOJOクラスがないマッピングの例です。
これはPOJOクラスがないマッピングの例です。
</para>
<programlisting><![CDATA[<class entity-name="Account"
@ -99,11 +101,11 @@
</class>]]></programlisting>
<para>
このマッピングにより、dom4jツリーか、
プロパティ名/値の組のグラフjavaの <literal>Map</literal>)として
データにアクセスできます。
このマッピングにより、dom4jツリーか、
プロパティ名/値の組のグラフjavaの <literal>Map</literal>)として
データにアクセスできます。
プロパティの名前は、HQLクエリー内で参照できる純粋な論理構造です。
プロパティの名前は、HQLクエリー内で参照できる純粋な論理構造です。
</para>
</sect2>
@ -111,53 +113,53 @@
</sect1>
<sect1 id="xml-mapping" revision="1">
<title>XMLマッピングのメタデータ</title>
<title>XMLマッピングのメタデータ</title>
<para>
多くのHibernateのマッピング要素は <literal>node</literal> 属性が使用できます。
これによりXML属性の名前やプロパティやエンティティデータを保持する要素を指定できます。
<literal>node</literal> 属性のフォーマットは以下の中の1つでなければなりません。
多くのHibernateのマッピング要素は <literal>node</literal> 属性が使用できます。
これによりXML属性の名前やプロパティやエンティティデータを保持する要素を指定できます。
<literal>node</literal> 属性のフォーマットは以下の中の1つでなければなりません。
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
<literal>"element-name"</literal> - 指定したXML要素へマッピングします
<literal>"element-name"</literal> - 指定したXML要素へマッピングします
</para>
</listitem>
<listitem>
<para>
<literal>"@attribute-name"</literal> - 指定したXML属性へマッピングします
<literal>"@attribute-name"</literal> - 指定したXML属性へマッピングします
</para>
</listitem>
<listitem>
<para>
<literal>"."</literal> - 親要素へマッピングします
<literal>"."</literal> - 親要素へマッピングします
</para>
</listitem>
<listitem>
<para>
<literal>"element-name/@attribute-name"</literal> -
指定したエレメントの指定した属性へマッピングします
指定したエレメントの指定した属性へマッピングします
</para>
</listitem>
</itemizedlist>
<para>
コレクションと単一の値の関連に対して、
おまけの <literal>embed-xml</literal> 属性があります。
デフォルトの <literal>embed-xml="true"</literal> と設定した場合、
関連するエンティティ(値型のコレクション)のXMLツリーは、
直接関連を所有するエンティティのXMLツリー内に埋め込まれます。
反対に、<literal>embed-xml="false"</literal> と設定した場合、
参照される識別子の値だけが多重度側の関連に対するXMLに現れ、
単純にコレクションはまったく現れなくなります。
コレクションと単一の値の関連に対して、
おまけの <literal>embed-xml</literal> 属性があります。
デフォルトの <literal>embed-xml="true"</literal> と設定した場合、
関連するエンティティ(値型のコレクション)のXMLツリーは、
直接関連を所有するエンティティのXMLツリー内に埋め込まれます。
反対に、<literal>embed-xml="false"</literal> と設定した場合、
参照される識別子の値だけが多重度側の関連に対するXMLに現れ、
単純にコレクションはまったく現れなくなります。
</para>
<para>
あまりに多くの関連に対して
<literal>embed-xml="true"</literal> としたままにするのは注意すべきです。
XMLは循環をうまく扱えません。
あまりに多くの関連に対して
<literal>embed-xml="true"</literal> としたままにするのは注意すべきです。
XMLは循環をうまく扱えません。
</para>
<programlisting><![CDATA[<class name="Customer"
@ -196,15 +198,15 @@
</class>]]></programlisting>
<para>
この例では、実際のaccountのデータではなく、
accountのidのコレクションを埋め込むことにしました。
続きのHQLクエリです
この例では、実際のaccountのデータではなく、
accountのidのコレクションを埋め込むことにしました。
続きのHQLクエリです
</para>
<programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
<para>
このようなデータセットを返すでしょう
このようなデータセットを返すでしょう
</para>
<programlisting><![CDATA[<customer id="123456789">
@ -219,9 +221,9 @@
</customer>]]></programlisting>
<para>
<literal>&lt;one-to-many&gt;</literal> マッピングで
<literal>embed-xml="true"</literal> と設定した場合、
データはこのようになるでしょう。
<literal>&lt;one-to-many&gt;</literal> マッピングで
<literal>embed-xml="true"</literal> と設定した場合、
データはこのようになるでしょう。
</para>
<programlisting><![CDATA[<customer id="123456789">
@ -245,11 +247,11 @@
<sect1 id="xml-manipulation" revision="1">
<title>XMLデータを扱う</title>
<title>XMLデータを扱う</title>
<para>
XMLドキュメントを、アプリケーション内で再読み込みや更新をしてみましょう。
以下ではdom4jのセッションを取得することで行います。
XMLドキュメントを、アプリケーション内で再読み込みや更新をしてみましょう。
以下ではdom4jのセッションを取得することで行います。
</para>
<programlisting><![CDATA[Document doc = ....;
@ -288,9 +290,9 @@ tx.commit();
session.close();]]></programlisting>
<para>
XMLベースのデータのインポート/エクスポートを実装するために、
Hibernateの <literal>replicate()</literal> 操作をこの機能を結びつけるのは
極めて有効です。
XMLベースのデータのインポート/エクスポートを実装するために、
Hibernateの <literal>replicate()</literal> 操作をこの機能を結びつけるのは
極めて有効です。
</para>
</sect1>

View File

@ -1,4 +1,4 @@
<?xml version='1.0'?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE legalnotice PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!--
@ -49,4 +49,4 @@
<para>
CA 20 86 86 2B D6 9D FC 65 F6 EC C4 21 91 80 CD DB 42 A6 0E
</para>
</legalnotice>
</legalnotice>