<?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>.
  -->
<chapter xml:id="associations"  xmlns="http://docbook.org/ns/docbook">

    <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 xml:id="assoc-unidirectional" revision="1">
        <title>Unidirectional associations</title>
        
        <section xml: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 xml: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 xml: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 xml:id="assoc-unidirectional-join" revision="1">
        <title>Unidirectional associations with join tables</title>
        
        <section xml: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 bigint not null, addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key )
        ]]></programlisting>
        
        </section>

        <section xml: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 xml: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 xml: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 xml:id="assoc-bidirectional" revision="1">
        <title>Bidirectional associations</title>
        
        <section xml: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 xml: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 xml:id="assoc-bidirectional-join" revision="1">
        <title>Bidirectional associations with join tables</title>
        
        <section xml: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 xml: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 xml: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 xml: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>

