<?xml version='1.0' encoding="UTF-8"?>
<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
  ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
  -->
<!DOCTYPE chapter SYSTEM "http://docbook.org/xml/5.0/dtd/docbook.dtd">

<chapter xml:id="example-mappings" xmlns="http://docbook.org/ns/docbook">
    <title>Example: Various Mappings</title>
   

    <para>
        This chapters explores some more complex association mappings.
    </para>
    
    <section xml:id="example-mappings-emp">
        <title>Employer/Employee</title>

        <para>
            The following model of the relationship between <literal>Employer</literal> and 
            <literal>Employee</literal> uses an entity class (<literal>Employment</literal>) 
            to represent the association. You can do this when there might be more than one
            period of employment for the same two parties. Components are used to model monetary 
            values and employee names.
        </para>

        <mediaobject>
            <imageobject role="html">
                <imagedata fileref="images/EmployerEmployee.png" format="PNG" align="center" />
            </imageobject>
            <imageobject role="fo">
                <imagedata fileref="images/EmployerEmployee.png" format="PNG" align="center" width="17cm" />
            </imageobject>
        </mediaobject>
        
        <para>
            Here is a possible mapping document:
        </para>
        
        <programlisting role="XML"><![CDATA[<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>]]></programlisting>

    <para>
        Here is the table schema generated by <literal>SchemaExport</literal>.
    </para>

    <programlisting><![CDATA[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]]></programlisting>

    </section>
    
    <section xml:id="example-mappings-authorwork">
        <title>Author/Work</title>

        <para>
            Consider the following model of the relationships between <literal>Work</literal>,
            <literal>Author</literal> and <literal>Person</literal>. In the example, the relationship
            between <literal>Work</literal> and <literal>Author</literal> is represented as a many-to-many
            association and the relationship between <literal>Author</literal> 
            and <literal>Person</literal> is represented as one-to-one association. Another possibility would be to 
            have <literal>Author</literal> extend <literal>Person</literal>.  
        </para>

        <mediaobject>
            <imageobject role="html">
                <imagedata fileref="images/AuthorWork.png" format="PNG" align="center" />
            </imageobject>
            <imageobject role="fo">
                <imagedata fileref="images/AuthorWork.png" format="PNG" align="center" width="17cm" />
            </imageobject>
        </mediaobject>
        
        <para>
            The following mapping document correctly represents these relationships:
        </para>
        
        <programlisting role="XML"><![CDATA[<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>]]></programlisting>

    <para>
        There are four tables in this mapping: <literal>works</literal>,
        <literal>authors</literal> and <literal>persons</literal> hold work, author
        and person data respectively. <literal>author_work</literal> is an association
        table linking authors to works. Here is the table schema, as generated by
        <literal>SchemaExport</literal>:
    </para>

    <programlisting><![CDATA[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]]></programlisting>

    </section>

    <section xml:id="example-mappings-customerorderproduct">
        <title>Customer/Order/Product</title>

        <para>
            In this section we consider a model of the relationships between <literal>Customer</literal>,
            <literal>Order</literal>, <literal>Line Item</literal> and <literal>Product</literal>.
            There is a one-to-many association between <literal>Customer</literal> and
            <literal>Order</literal>, but how can you represent <literal>Order</literal> / 
            <literal>LineItem</literal> / <literal>Product</literal>? In the example, 
            <literal>LineItem</literal> is mapped as an association class representing the many-to-many
            association between <literal>Order</literal> and <literal>Product</literal>. In
            Hibernate this is called a composite element.
        </para>

        <mediaobject>
            <imageobject role="html">
                <imagedata fileref="images/CustomerOrderProduct.png" format="PNG" align="center" />
            </imageobject>
            <imageobject role="fo">
                <imagedata fileref="images/CustomerOrderProduct.png" format="PNG" align="center" width="17cm" />
            </imageobject>
        </mediaobject>
        
        <para>
            The mapping document will look like this:
        </para>
        
        <programlisting role="XML"><![CDATA[<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>]]></programlisting>

    <para>
        <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> and 
        <literal>products</literal> hold customer, order, order line item and product data
        respectively. <literal>line_items</literal> also acts as an association table linking
        orders with products.
    </para>

    <programlisting><![CDATA[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]]></programlisting>

    </section>
    
    <section xml:id="misc">
        <title>Miscellaneous example mappings</title>
        
        <para>
            These examples are available from the Hibernate test suite. You
            will find many other useful example mappings there by searching in the
            <literal>test</literal> folder of the Hibernate distribution.
        </para>
        
      <!--  <<para>TODO: put words around this stuff</para>-->
        
        <section xml:id="example-mappings-typed-onetone">
            <title>"Typed" one-to-one association</title>
<programlisting role="XML"><![CDATA[<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>]]></programlisting>
        </section>
        
        <section xml:id="example-mappings-composite-key">
            <title>Composite key example</title>
<programlisting role="XML"><![CDATA[<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>]]></programlisting>
        </section>
        
        <section xml:id="example-mappings-composite-key-manytomany">
            <title>Many-to-many with shared composite key attribute</title>
<programlisting role="XML"><![CDATA[<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>
]]></programlisting>
        </section>

        <section xml:id="example-mappings-content-discrimination">
            <title>Content based discrimination</title>
<programlisting role="XML"><![CDATA[<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>]]></programlisting>
        </section>

        <section xml:id="example-mappings-association-alternatekeys" revision="2">
            <title>Associations on alternate keys</title>
<programlisting role="XML"><![CDATA[<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>]]></programlisting>
        </section>

    </section>

</chapter>

