<?xml version='1.0' encoding="UTF-8"?>
<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
  ~ indicated by the @author tags or express copyright attribution
  ~ statements applied by the authors.  All third-party contributions are
  ~ distributed under license by Red Hat Middleware LLC.
  ~
  ~ This copyrighted material is made available to anyone wishing to use, modify,
  ~ copy, or redistribute it subject to the terms and conditions of the GNU
  ~ Lesser General Public License, as published by the Free Software Foundation.
  ~
  ~ This program is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->

<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;

]>

<chapter id="associations">

    <title>Association Mappings</title>

    <section id="assoc-intro" revision="1">
        <title>Introduction</title>
        
        <para>
            Association mappings are often the most difficult thing to implement correctly. In
            this section we examine some canonical cases one by one, starting
            with unidirectional mappings and then bidirectional cases.
            We will use <literal>Person</literal> and <literal>Address</literal> in all
            the examples.
        </para>
        
        <para>
        	Associations will be classified by multiplicity and whether or not they map to an intervening
        	join table.
        </para>
        
        <para>
        	Nullable foreign keys are not considered to be good practice in traditional data
        	modelling, so our examples do not use nullable foreign keys. This is not a
        	requirement of Hibernate, and the mappings will work if you drop the
        	nullability constraints.
        </para>
        
    </section>

    <section id="assoc-unidirectional" revision="1">
        <title>Unidirectional associations</title>
        
        <section id="assoc-unidirectional-m21">
        <title>Many-to-one</title>
        
        <para>
            A <emphasis>unidirectional many-to-one association</emphasis> is the most 
            common kind of unidirectional association.
        </para>
        
        <programlisting role="XML"><![CDATA[<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>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>

        <section id="assoc-unidirectional-121">
        <title>One-to-one</title>
        
        <para>
            A <emphasis>unidirectional one-to-one association on a foreign key</emphasis>
            is almost identical. The only difference is the column unique constraint.
        </para>
        
       <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <many-to-one name="address" 
        column="addressId" 
        unique="true"
        not-null="true"/>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        <para>
            A <emphasis>unidirectional one-to-one association on a primary key</emphasis>
            usually uses a special id generator In this example, however, we have reversed the direction
            of the association:
        </para>
        
       <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
</class>

<class name="Address">
    <id name="id" column="personId">
        <generator class="foreign">
            <param name="property">person</param>
        </generator>
    </id>
    <one-to-one name="person" constrained="true"/>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )
        ]]></programlisting>
        
        </section>
        
        <section id="assoc-unidirectional-12m">
        <title>One-to-many</title>
        
        <para>
            A <emphasis>unidirectional one-to-many association on a foreign key</emphasis> 
            is an unusual case, and is not recommended.
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <set name="addresses">
        <key column="personId" 
            not-null="true"/>
        <one-to-many class="Address"/>
    </set>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table Address ( addressId bigint not null primary key, personId bigint not null )
        ]]></programlisting>
        
        <para>
          You should instead use a join table for this kind of association.
        </para>
        
        </section>
    
    </section>

    <section id="assoc-unidirectional-join" revision="1">
        <title>Unidirectional associations with join tables</title>
        
        <section id="assoc-unidirectional-join-12m">
        <title>One-to-many</title>
        
        <para>
            A <emphasis>unidirectional one-to-many association on a join table</emphasis> 
            is the preferred option. Specifying <literal>unique="true"</literal>,
            changes the multiplicity from many-to-many to one-to-many.
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <set name="addresses" table="PersonAddress">
        <key column="personId"/>
        <many-to-many column="addressId"
            unique="true"
            class="Address"/>
    </set>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId not null, addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>

        <section id="assoc-unidirectional-join-m21">
        <title>Many-to-one</title>
        
        <para>
            A <emphasis>unidirectional many-to-one association on a join table</emphasis> 
            is common when the association is optional. For example:
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <join table="PersonAddress" 
        optional="true">
        <key column="personId" unique="true"/>
        <many-to-one name="address"
            column="addressId" 
            not-null="true"/>
    </join>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>

        <section id="assoc-unidirectional-join-121">
        <title>One-to-one</title>
        
        <para>
            A <emphasis>unidirectional one-to-one association on a join table</emphasis> is possible, 
   	but extremely unusual.
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <join table="PersonAddress" 
        optional="true">
        <key column="personId" 
            unique="true"/>
        <many-to-one name="address"
            column="addressId" 
            not-null="true"
            unique="true"/>
    </join>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>

        <section id="assoc-unidirectional-join-m2m">
        <title>Many-to-many</title>
        
        <para>
            Finally, here is an example of a <emphasis>unidirectional many-to-many association</emphasis>.
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <set name="addresses" table="PersonAddress">
        <key column="personId"/>
        <many-to-many column="addressId"
            class="Address"/>
    </set>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>

    </section>

    <section id="assoc-bidirectional" revision="1">
        <title>Bidirectional associations</title>
        
        <section id="assoc-bidirectional-m21" revision="2">
        <title>one-to-many / many-to-one</title>
        
        <para>
            A <emphasis>bidirectional many-to-one association</emphasis> is the
            most common kind of association. The following example illustrates the standard parent/child
            relationship.
        </para>
        
        <programlisting role="XML"><![CDATA[<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>]]></programlisting>

        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>

        <para>
            If you use a <literal>List</literal>, or other indexed collection,
            set the <literal>key</literal> column of the foreign key to <literal>not null</literal>.
            Hibernate will manage the association from the collections side to maintain the index
            of each element, making the other side virtually inverse by setting
            <literal>update="false"</literal> and <literal>insert="false"</literal>:
        </para>

        <programlisting role="XML"><![CDATA[<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>]]></programlisting>

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

        </section>
        
        <section id="assoc-bidirectional-121">
        <title>One-to-one</title>
        
        <para>
            A <emphasis>bidirectional one-to-one association on a foreign key</emphasis>
            is common:
        </para>
        
       <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <many-to-one name="address" 
        column="addressId" 
        unique="true"
        not-null="true"/>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
   <one-to-one name="person" 
        property-ref="address"/>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        <para>
            A <emphasis>bidirectional one-to-one association on a primary key</emphasis>
            uses the special id generator:
        </para>
        
       <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <one-to-one name="address"/>
</class>

<class name="Address">
    <id name="id" column="personId">
        <generator class="foreign">
            <param name="property">person</param>
        </generator>
    </id>
    <one-to-one name="person" 
        constrained="true"/>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )
        ]]></programlisting>
        
        </section>
        
    </section>

    <section id="assoc-bidirectional-join" revision="1">
        <title>Bidirectional associations with join tables</title>
        
        <section id="assoc-bidirectional-join-12m">
        <title>one-to-many / many-to-one</title>
        
        <para>
            The following is an example of a <emphasis>bidirectional one-to-many association on a join table</emphasis>.
            The <literal>inverse="true"</literal> can go on either end of the
            association, on the collection, or on the join.
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <set name="addresses" 
        table="PersonAddress">
        <key column="personId"/>
        <many-to-many column="addressId"
            unique="true"
            class="Address"/>
    </set>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
    <join table="PersonAddress" 
        inverse="true" 
        optional="true">
        <key column="addressId"/>
        <many-to-one name="person"
            column="personId"
            not-null="true"/>
    </join>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>

         <section id="assoc-bidirectional-join-121">
        <title>one to one</title>
        
        <para>
            A <emphasis>bidirectional one-to-one association on a join table</emphasis> is possible,
            but extremely unusual.
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <join table="PersonAddress" 
        optional="true">
        <key column="personId" 
            unique="true"/>
        <many-to-one name="address"
            column="addressId" 
            not-null="true"
            unique="true"/>
    </join>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
    <join table="PersonAddress" 
        optional="true"
        inverse="true">
        <key column="addressId" 
            unique="true"/>
        <many-to-one name="person"
            column="personId" 
            not-null="true"
            unique="true"/>
    </join>
</class>]]></programlisting>
        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>

        </section>
        
        <section id="assoc-bidirectional-join-m2m" revision="1">
        <title>Many-to-many</title>
        
        <para>
            Here is an example of a <emphasis>bidirectional many-to-many association</emphasis>.
        </para>
        
        <programlisting role="XML"><![CDATA[<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <set name="addresses" table="PersonAddress">
        <key column="personId"/>
        <many-to-many column="addressId"
            class="Address"/>
    </set>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
    <set name="people" inverse="true" table="PersonAddress">
        <key column="addressId"/>
        <many-to-many column="personId"
            class="Person"/>
    </set>
</class>]]></programlisting>

        <programlisting><![CDATA[
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>
        
    </section>
    
    <section id="assoc-complex">
        <title>More complex association mappings</title>
        
        <para>
            More complex association joins are <emphasis>extremely</emphasis> rare. 
            Hibernate handles more complex situations by using
            SQL fragments embedded in the mapping document. For example, if a table
            with historical account information data defines 
            <literal>accountNumber</literal>, <literal>effectiveEndDate</literal> 
            and <literal>effectiveStartDate</literal>columns, it would be mapped as follows:
        </para>
        
        <programlisting role="XML"><![CDATA[<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"/>]]></programlisting>

        <para>
            You can then map an association to the <emphasis>current</emphasis> instance, 
            the one with null <literal>effectiveEndDate</literal>, by using:
        </para>
        
        <programlisting role="XML"><![CDATA[<many-to-one name="currentAccountInfo"
        property-ref="currentAccountKey"
        class="AccountInfo">
    <column name="accountNumber"/>
    <formula>'1'</formula>
</many-to-one>]]></programlisting>

        <para>
            In a more complex example, imagine that the association between 
            <literal>Employee</literal> and <literal>Organization</literal> is maintained
            in an <literal>Employment</literal> table full of historical employment data.
            An association to the employee's <emphasis>most recent</emphasis> employer,
            the one with the most recent <literal>startDate</literal>, could be mapped in the following way:
        </para>
        
        <programlisting role="XML"><![CDATA[<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>]]></programlisting>

        <para>
            This functionality allows a degree of creativity and flexibility, but it is more practical 
            to handle these kinds of cases using HQL or a criteria query.
        </para>

    </section>

</chapter>

