Hibernate.orgCommunity Documentation

第8章 関連マッピング

8.1. イントロダクション
8.2. 単方向関連
8.2.1. Many-to-one
8.2.2. One-to-one
8.2.3. One-to-many
8.3. 結合テーブルを使った単方向関連
8.3.1. One-to-many
8.3.2. Many-to-one
8.3.3. One-to-one
8.3.4. Many-to-many
8.4. 双方向関連
8.4.1. 一対多/多対一
8.4.2. One-to-one
8.5. 結合テーブルを使った双方向関連
8.5.1. 一対多/多対一
8.5.2. 一対一
8.5.3. Many-to-many
8.6. より複雑な関連マッピング

関連マッピングはしばしば理解が最も難しいものになります。この章では、基本的な一つ一つのケースについて述べます。単方向のマッピングから始め、それから双方向のケースについて考えていきます。例として、 PersonAddress を用います。

関連は、結合テーブルを入れるかかどうかと、多重度によって分類することにします。

null 可能な外部キーは従来型データモデリングの中では良い習慣と見なされていないため、すべての例で not null の外部キーを使用します。これは Hibernate の要件ではありません。 not null 制約を外したとしても、マッピングは問題なく動作します。

双方向多対一関連 は最も一般的な関連です。 (標準的な親子関係です)


<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <many-to-one name="address" 
        column="addressId"
        not-null="true"/>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
    <set name="people" inverse="true">
        <key column="addressId"/>
        <one-to-many class="Person"/>
    </set>
</class
>
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
        

List (または他のインデックス付きのコレクション)を使うなら、外部キーの key カラムを not null に設定し、コレクション側が各要素のインデックスをメンテナンスするように、関連を扱う必要があります (update="false" かつ insert="false" と設定して、反対側を仮想的に inverse にします):


<class name="Person">
   <id name="id"/>
   ...
   <many-to-one name="address"
      column="addressId"
      not-null="true"
      insert="false"
      update="false"/>
</class>

<class name="Address">
   <id name="id"/>
   ...
   <list name="people">
      <key column="addressId" not-null="true"/>
      <list-index column="peopleIdx"/>
      <one-to-many class="Person"/>
   </list>
</class
>

If the underlying foreign key column is NOT NULL, it is important that you define not-null="true" on the <key> element of the collection mapping. Do not only declare not-null="true" on a possible nested <column> element, but on the <key> element.

より複雑な関連結合は 極めて 稀です。マッピングドキュメントに SQL 文を埋め込むことで、さらに複雑な状況を扱うことができます。例えば、 accountNumbereffectiveEndDateeffectiveStartDate カラムを持つ account (口座)情報の履歴を扱うテーブルは、以下のようにマッピングします。


<properties name="currentAccountKey">
    <property name="accountNumber" type="string" not-null="true"/>
    <property name="currentAccount" type="boolean">
        <formula
>case when effectiveEndDate is null then 1 else 0 end</formula>
    </property>
</properties>
<property name="effectiveEndDate" type="date"/>
<property name="effectiveStateDate" type="date" not-null="true"/>

そして、関連を 現時点の インスタンス (effectiveEndDate が null であるもの)にマッピングします。以下のようになります:


<many-to-one name="currentAccountInfo"
        property-ref="currentAccountKey"
        class="AccountInfo">
    <column name="accountNumber"/>
    <formula
>'1'</formula>
</many-to-one
>

さらに複雑な例では、 Employee(従業員)Organization(組織) 間の関連が Employment(雇用) テーブルで保持される場合を想像してください。このテーブルには雇用データの履歴がすべて含まれます。すると従業員の 最も最近の 雇用者を表す関連 (最も最近の startDate を持つもの)は、このようにマッピングできます:


<join>
    <key column="employeeId"/>
    <subselect>
        select employeeId, orgId 
        from Employments 
        group by orgId 
        having startDate = max(startDate)
    </subselect>
    <many-to-one name="mostRecentEmployer" 
            class="Organization" 
            column="orgId"/>
</join
>

この機能は非常に強力です。しかしこのような場合、普通は HQL や criteria クエリを使う方がより実践的です。