Hibernate.org Community Documentation

- 前のページ
- 次のページ

## 第26章 例： いろいろなマッピング

この章では、より複雑な関連のマッピングをいくつか紹介します。

## 26.1. 雇用者/従業員

`Employer` と `Employee` の関係を表す以下のモデルは、関連の表現に実際のエンティティクラス （ `Employment` ） を使います。なぜなら、同じ2つのパーティに複数の期間雇用されるということがありえるからです。お金の値と従業員の名前をモデル化するためにコンポーネントを使っています。

マッピングドキュメントの一例です：

    <hibernate-mapping>

        <class name="Employer" table="employers">

            <id name="id">

                <generator class="sequence">

                    <param name="sequence"

    >employer_id_seq</param>

                </generator>

            </id>

            <property name="name"/>

        </class>

        <class name="Employment" table="employment_periods">

            <id name="id">

                <generator class="sequence">

                    <param name="sequence"

    >employment_id_seq</param>

                </generator>

            </id>

            <property name="startDate" column="start_date"/>

            <property name="endDate" column="end_date"/>

            <component name="hourlyRate" class="MonetaryAmount">

                <property name="amount">

                    <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>

                </property>

                <property name="currency" length="12"/>

            </component>

            <many-to-one name="employer" column="employer_id" not-null="true"/>

            <many-to-one name="employee" column="employee_id" not-null="true"/>

        </class>

        <class name="Employee" table="employees">

            <id name="id">

                <generator class="sequence">

                    <param name="sequence"

    >employee_id_seq</param>

                </generator>

            </id>

            <property name="taxfileNumber"/>

            <component name="name" class="Name">

                <property name="firstName"/>

                <property name="initial"/>

                <property name="lastName"/>

            </component>

        </class>

    </hibernate-mapping

    >

`SchemaExport` で生成したテーブルスキーマです。

    create table employers (
        id BIGINT not null,
        name VARCHAR(255),
        primary key (id)
    )

    create table employment_periods (
        id BIGINT not null,
        hourly_rate NUMERIC(12, 2),
        currency VARCHAR(12),
        employee_id BIGINT not null,
        employer_id BIGINT not null,
        end_date TIMESTAMP,
        start_date TIMESTAMP,
        primary key (id)
    )

    create table employees (
        id BIGINT not null,
        firstName VARCHAR(255),
        initial CHAR(1),
        lastName VARCHAR(255),
        taxfileNumber VARCHAR(255),
        primary key (id)
    )

    alter table employment_periods
        add constraint employment_periodsFK0 foreign key (employer_id) references employers
    alter table employment_periods
        add constraint employment_periodsFK1 foreign key (employee_id) references employees
    create sequence employee_id_seq
    create sequence employment_id_seq
    create sequence employer_id_seq

## 26.2. 作者/作品

`Work` 、 `Author` そして `Person` の関係を表す以下のモデルを考えてみてください。 `Work` と `Author` の関係を多対多関連で表しています。 `Author` と `Person` の関係は一対一関連として表しています。他には `Author` が `Person` を拡張するという方法もあります。

以下のマッピングドキュメントはこのような関係を正確に表現しています:

    <hibernate-mapping>

        <class name="Work" table="works" discriminator-value="W">

            <id name="id" column="id">

                <generator class="native"/>

            </id>

            <discriminator column="type" type="character"/>

            <property name="title"/>

            <set name="authors" table="author_work">

                <key column name="work_id"/>

                <many-to-many class="Author" column name="author_id"/>

            </set>

            <subclass name="Book" discriminator-value="B">

                <property name="text"/>

            </subclass>

            <subclass name="Song" discriminator-value="S">

                <property name="tempo"/>

                <property name="genre"/>

            </subclass>

        </class>

        <class name="Author" table="authors">

            <id name="id" column="id">

                <!-- The Author must have the same identifier as the Person -->

                <generator class="assigned"/>

            </id>

            <property name="alias"/>

            <one-to-one name="person" constrained="true"/>

            <set name="works" table="author_work" inverse="true">

                <key column="author_id"/>

                <many-to-many class="Work" column="work_id"/>

            </set>

        </class>

        <class name="Person" table="persons">

            <id name="id" column="id">

                <generator class="native"/>

            </id>

            <property name="name"/>

        </class>

    </hibernate-mapping

    >

このマッピングには4つのテーブルがあります。 `works` 、 `authors` , `persons` はそれぞれ、仕事、作者、人のデータを保持します。 `author_work` は作者と作品をリンクする関連テーブルです。以下は `SchemaExport` で生成したテーブルスキーマです。

    create table works (
        id BIGINT not null generated by default as identity,
        tempo FLOAT,
        genre VARCHAR(255),
        text INTEGER,
        title VARCHAR(255),
        type CHAR(1) not null,
        primary key (id)
    )

    create table author_work (
        author_id BIGINT not null,
        work_id BIGINT not null,
        primary key (work_id, author_id)
    )

    create table authors (
        id BIGINT not null generated by default as identity,
        alias VARCHAR(255),
        primary key (id)
    )

    create table persons (
        id BIGINT not null generated by default as identity,
        name VARCHAR(255),
        primary key (id)
    )

    alter table authors
        add constraint authorsFK0 foreign key (id) references persons
    alter table author_work
        add constraint author_workFK0 foreign key (author_id) references authors
    alter table author_work
        add constraint author_workFK1 foreign key (work_id) references works

## 26.3. 顧客/注文/製品

さて、 `Customer` 、 `Order` 、 `LineItem` 、 `Product` の関係を表すモデルを考えてみましょう。 `Customer` と `Order` は一対多の関連ですが、 `Order` / `LineItem` / `Product` はどのように表現するべきでしょうか？ `LineItem` を、 `Order` と `Product` の多対多関連を表現する関連クラスとしてマッピングしました。 Hibernate ではこれをコンポジット要素と呼びます。

マッピングドキュメント：

    <hibernate-mapping>

        <class name="Customer" table="customers">

            <id name="id">

                <generator class="native"/>

            </id>

            <property name="name"/>

            <set name="orders" inverse="true">

                <key column="customer_id"/>

                <one-to-many class="Order"/>

            </set>

        </class>

        <class name="Order" table="orders">

            <id name="id">

                <generator class="native"/>

            </id>

            <property name="date"/>

            <many-to-one name="customer" column="customer_id"/>

            <list name="lineItems" table="line_items">

                <key column="order_id"/>

                <list-index column="line_number"/>

                <composite-element class="LineItem">

                    <property name="quantity"/>

                    <many-to-one name="product" column="product_id"/>

                </composite-element>

            </list>

        </class>

        <class name="Product" table="products">

            <id name="id">

                <generator class="native"/>

            </id>

            <property name="serialNumber"/>

        </class>

    </hibernate-mapping

    >

`customers` 、 `orders` 、 `line_items` 、 `products` はそれぞれ、顧客、注文、注文明細、製品のデータを保持します。 `line_items` は注文と製品をリンクする関連テーブルとしても働きます。

    create table customers (
        id BIGINT not null generated by default as identity,
        name VARCHAR(255),
        primary key (id)
    )

    create table orders (
        id BIGINT not null generated by default as identity,
        customer_id BIGINT,
        date TIMESTAMP,
        primary key (id)
    )

    create table line_items (
        line_number INTEGER not null,
        order_id BIGINT not null,
        product_id BIGINT,
        quantity INTEGER,
        primary key (order_id, line_number)
    )

    create table products (
        id BIGINT not null generated by default as identity,
        serialNumber VARCHAR(255),
        primary key (id)
    )

    alter table orders
        add constraint ordersFK0 foreign key (customer_id) references customers
    alter table line_items
        add constraint line_itemsFK0 foreign key (product_id) references products
    alter table line_items
        add constraint line_itemsFK1 foreign key (order_id) references orders

## 26.4. 種々雑多なマッピング例

ここにある例はすべて Hibernate のテストスイートから取りました。そこには、他にもたくさんのマッピングの例があります。 Hibernate ディストリビューションの `test` フォルダを見てください。

### 26.4.1. 「型付けされた」一対一関連

    <class name="Person">

        <id name="name"/>

        <one-to-one name="address"

                cascade="all">

            <formula

    >name</formula>

            <formula

    >'HOME'</formula>

        </one-to-one>

        <one-to-one name="mailingAddress"

                cascade="all">

            <formula

    >name</formula>

            <formula

    >'MAILING'</formula>

        </one-to-one>

    </class>

    <class name="Address" batch-size="2"

            check="addressType in ('MAILING', 'HOME', 'BUSINESS')">

        <composite-id>

            <key-many-to-one name="person"

                    column="personName"/>

            <key-property name="type"

                    column="addressType"/>

        </composite-id>

        <property name="street" type="text"/>

        <property name="state"/>

        <property name="zip"/>

    </class

    >

### 26.4.2. 複合キーの例

    <class name="Customer">

        <id name="customerId"

            length="10">

            <generator class="assigned"/>

        </id>

        <property name="name" not-null="true" length="100"/>

        <property name="address" not-null="true" length="200"/>

        <list name="orders"

                inverse="true"

                cascade="save-update">

            <key column="customerId"/>

            <index column="orderNumber"/>

            <one-to-many class="Order"/>

        </list>

    </class>

    <class name="Order" table="CustomerOrder" lazy="true">

        <synchronize table="LineItem"/>

        <synchronize table="Product"/>

        <composite-id name="id"

                class="Order$Id">

            <key-property name="customerId" length="10"/>

            <key-property name="orderNumber"/>

        </composite-id>

        <property name="orderDate"

                type="calendar_date"

                not-null="true"/>

        <property name="total">

            <formula>

                ( select sum(li.quantity*p.price)

                from LineItem li, Product p

                where li.productId = p.productId

                    and li.customerId = customerId

                    and li.orderNumber = orderNumber )

            </formula>

        </property>

        <many-to-one name="customer"

                column="customerId"

                insert="false"

                update="false"

                not-null="true"/>

        <bag name="lineItems"

                fetch="join"

                inverse="true"

                cascade="save-update">

            <key>

                <column name="customerId"/>

                <column name="orderNumber"/>

            </key>

            <one-to-many class="LineItem"/>

        </bag>

    </class>

    <class name="LineItem">

        <composite-id name="id"

                class="LineItem$Id">

            <key-property name="customerId" length="10"/>

            <key-property name="orderNumber"/>

            <key-property name="productId" length="10"/>

        </composite-id>

        <property name="quantity"/>

        <many-to-one name="order"

                insert="false"

                update="false"

                not-null="true">

            <column name="customerId"/>

            <column name="orderNumber"/>

        </many-to-one>

        <many-to-one name="product"

                insert="false"

                update="false"

                not-null="true"

                column="productId"/>

    </class>

    <class name="Product">

        <synchronize table="LineItem"/>

        <id name="productId"

            length="10">

            <generator class="assigned"/>

        </id>

        <property name="description"

            not-null="true"

            length="200"/>

        <property name="price" length="3"/>

        <property name="numberAvailable"/>

        <property name="numberOrdered">

            <formula>

                ( select sum(li.quantity)

                from LineItem li

                where li.productId = productId )

            </formula>

        </property>

    </class

    >

### 26.4.3. 複合キー属性を共有する多対多

    <class name="User" table="`User`">

        <composite-id>

            <key-property name="name"/>

            <key-property name="org"/>

        </composite-id>

        <set name="groups" table="UserGroup">

            <key>

                <column name="userName"/>

                <column name="org"/>

            </key>

            <many-to-many class="Group">

                <column name="groupName"/>

                <formula

    >org</formula>

            </many-to-many>

        </set>

    </class>

    <class name="Group" table="`Group`">

        <composite-id>

            <key-property name="name"/>

            <key-property name="org"/>

        </composite-id>

        <property name="description"/>

        <set name="users" table="UserGroup" inverse="true">

            <key>

                <column name="groupName"/>

                <column name="org"/>

            </key>

            <many-to-many class="User">

                <column name="userName"/>

                <formula

    >org</formula>

            </many-to-many>

        </set>

    </class>

### 26.4.4. discrimination に基づく内容

    <class name="Person"

        discriminator-value="P">

        <id name="id"

            column="person_id"

            unsaved-value="0">

            <generator class="native"/>

        </id>

        <discriminator

            type="character">

            <formula>

                case

                    when title is not null then 'E'

                    when salesperson is not null then 'C'

                    else 'P'

                end

            </formula>

        </discriminator>

        <property name="name"

            not-null="true"

            length="80"/>

        <property name="sex"

            not-null="true"

            update="false"/>

        <component name="address">

            <property name="address"/>

            <property name="zip"/>

            <property name="country"/>

        </component>

        <subclass name="Employee"

            discriminator-value="E">

                <property name="title"

                    length="20"/>

                <property name="salary"/>

                <many-to-one name="manager"/>

        </subclass>

        <subclass name="Customer"

            discriminator-value="C">

                <property name="comments"/>

                <many-to-one name="salesperson"/>

        </subclass>

    </class

    >

### 26.4.5. 代替キーの関連

    <class name="Person">

        <id name="id">

            <generator class="hilo"/>

        </id>

        <property name="name" length="100"/>

        <one-to-one name="address"

            property-ref="person"

            cascade="all"

            fetch="join"/>

        <set name="accounts"

            inverse="true">

            <key column="userId"

                property-ref="userId"/>

            <one-to-many class="Account"/>

        </set>

        <property name="userId" length="8"/>

    </class>

    <class name="Address">

        <id name="id">

            <generator class="hilo"/>

        </id>

        <property name="address" length="300"/>

        <property name="zip" length="5"/>

        <property name="country" length="25"/>

        <many-to-one name="person" unique="true" not-null="true"/>

    </class>

    <class name="Account">

        <id name="accountId" length="32">

            <generator class="uuid"/>

        </id>

        <many-to-one name="user"

            column="userId"

            property-ref="userId"/>

        <property name="type" not-null="true"/>

    </class

    >

製作著作 © 2004 Red Hat, Inc.

- 前のページ第25章 例: Weblog アプリケーション
- 上に戻る
- ホーム
- 次のページ第27章 ベストプラクティス