<?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="components" xmlns="http://docbook.org/ns/docbook">
    <title>Component Mapping</title>

    <para>
        The notion of a <emphasis>component</emphasis> is re-used in several different contexts and purposes
        throughout Hibernate.
    </para>

    <section xml:id="components-dependentobjects" revision="2" >
        <title>Dependent objects</title>

        <para>
            A component is a contained object that is persisted as a value type and not an entity
            reference. The term "component" refers to the object-oriented notion of composition
             and not to architecture-level components. For example, you can model a person like this:
        </para>

        <programlisting role="JAVA"><![CDATA[public class Person {
    private java.util.Date birthday;
    private Name name;
    private String key;
    public String getKey() {
        return key;
    }
    private void setKey(String key) {
        this.key=key;
    }
    public java.util.Date getBirthday() {
        return birthday;
    }
    public void setBirthday(java.util.Date birthday) {
        this.birthday = birthday;
    }
    public Name getName() {
        return name;
    }
    public void setName(Name name) {
        this.name = name;
    }
    ......
    ......
}]]></programlisting>

<programlisting role="JAVA"><![CDATA[public class Name {
    char initial;
    String first;
    String last;
    public String getFirst() {
        return first;
    }
    void setFirst(String first) {
        this.first = first;
    }
    public String getLast() {
        return last;
    }
    void setLast(String last) {
        this.last = last;
    }
    public char getInitial() {
        return initial;
    }
    void setInitial(char initial) {
        this.initial = initial;
    }
}]]></programlisting>

        <para>
            Now <literal>Name</literal> can be persisted as a component of
            <literal>Person</literal>. <literal>Name</literal> defines getter
            and setter methods for its persistent properties, but it does not need to declare
            any interfaces or identifier properties.
        </para>

        <para>
            Our Hibernate mapping would look like this:
        </para>

        <programlisting role="XML"><![CDATA[<class name="eg.Person" table="person">
    <id name="Key" column="pid" type="string">
        <generator class="uuid"/>
    </id>
    <property name="birthday" type="date"/>
    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
        <property name="initial"/>
        <property name="first"/>
        <property name="last"/>
    </component>
</class>]]></programlisting>

        <para>
            The person table would have the columns <literal>pid</literal>,
            <literal>birthday</literal>,
            <literal>initial</literal>,
            <literal>first</literal> and
            <literal>last</literal>.
        </para>

        <para>
            Like value types, components do not support shared references. In other words, two
            persons could have the same name, but the two person objects would contain two independent
            name objects that were only "the same" by value. The null value semantics of a component are
            <emphasis>ad hoc</emphasis>. When reloading the containing object, Hibernate will assume
            that if all component columns are null, then the entire component is null. This is suitable for most purposes.
        </para>

        <para>
            The properties of a component can be of any Hibernate type (collections, many-to-one
            associations, other components, etc). Nested components should <emphasis>not</emphasis>
            be considered an exotic usage. Hibernate is intended to support a fine-grained
            object model.
        </para>

        <para>
            The <literal>&lt;component&gt;</literal> element allows a <literal>&lt;parent&gt;</literal>
            subelement that maps a property of the component class as a reference back to the
            containing entity.
        </para>

        <programlisting role="XML"><![CDATA[<class name="eg.Person" table="person">
    <id name="Key" column="pid" type="string">
        <generator class="uuid"/>
    </id>
    <property name="birthday" type="date"/>
    <component name="Name" class="eg.Name" unique="true">
        <parent name="namedPerson"/> <!-- reference back to the Person -->
        <property name="initial"/>
        <property name="first"/>
        <property name="last"/>
    </component>
</class>]]></programlisting>

    </section>

    <section xml:id="components-incollections" revision="1">
        <title>Collections of dependent objects</title>

        <para>
            Collections of components are supported (e.g. an array of type
            <literal>Name</literal>). Declare your component collection by
            replacing the <literal>&lt;element&gt;</literal> tag with a
            <literal>&lt;composite-element&gt;</literal> tag:
        </para>

        <programlisting role="XML"><![CDATA[<set name="someNames" table="some_names" lazy="true">
    <key column="id"/>
    <composite-element class="eg.Name"> <!-- class attribute required -->
        <property name="initial"/>
        <property name="first"/>
        <property name="last"/>
    </composite-element>
</set>]]></programlisting>

	<important>
    	<para>
            If you define a <literal>Set</literal> of composite elements, it is
            important to implement <literal>equals()</literal> and
            <literal>hashCode()</literal> correctly.
        </para>
	</important>

        <para>
            Composite elements can contain components but not collections. If your
            composite element contains
            components, use the <literal>&lt;nested-composite-element&gt;</literal>
            tag. This case is a collection of components which
            themselves have components. You may want to consider if
            a one-to-many association is more appropriate. Remodel the
            composite element as an entity, but be aware that even though the Java model
            is the same, the relational model and persistence semantics are still
            slightly different.
        </para>

        <para>
            A composite element mapping does not support null-able properties
            if you are using a <literal>&lt;set&gt;</literal>. There is no separate primary key column
	    in the composite element table. Hibernate
            uses each column's value to identify a record when deleting objects,
            which is not possible with null values. You have to either use only
            not-null properties in a composite-element or choose a
            <literal>&lt;list&gt;</literal>, <literal>&lt;map&gt;</literal>,
            <literal>&lt;bag&gt;</literal> or <literal>&lt;idbag&gt;</literal>.
        </para>

        <para>
            A special case of a composite element is a composite element with a nested
            <literal>&lt;many-to-one&gt;</literal> element. This mapping allows
            you to map extra columns of a many-to-many association table to the
            composite element class. The following is a many-to-many association
            from <literal>Order</literal> to <literal>Item</literal>, where
            <literal>purchaseDate</literal>, <literal>price</literal> and
            <literal>quantity</literal> are properties of the association:
        </para>

        <programlisting role="XML"><![CDATA[<class name="eg.Order" .... >
    ....
    <set name="purchasedItems" table="purchase_items" lazy="true">
        <key column="order_id">
        <composite-element class="eg.Purchase">
            <property name="purchaseDate"/>
            <property name="price"/>
            <property name="quantity"/>
            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
        </composite-element>
    </set>
</class>]]></programlisting>

        <para>
            There cannot be a reference to the purchase on the other side for
            bidirectional association navigation. Components are value types and
            do not allow shared references. A single <literal>Purchase</literal> can be in the
            set of an <literal>Order</literal>, but it cannot be referenced by the <literal>Item</literal>
            at the same time.
        </para>

        <para>Even ternary (or quaternary, etc) associations are possible:</para>

        <programlisting role="XML"><![CDATA[<class name="eg.Order" .... >
    ....
    <set name="purchasedItems" table="purchase_items" lazy="true">
        <key column="order_id">
        <composite-element class="eg.OrderLine">
            <many-to-one name="purchaseDetails class="eg.Purchase"/>
            <many-to-one name="item" class="eg.Item"/>
        </composite-element>
    </set>
</class>]]></programlisting>

        <para>
            Composite elements can appear in queries using the same syntax as
            associations to other entities.
        </para>

    </section>

    <section xml:id="components-asmapindex">
        <title>Components as Map indices</title>

        <para>
            The <literal>&lt;composite-map-key&gt;</literal> element allows you to map a
            component class as the key of a <literal>Map</literal>. Ensure that you override
            <literal>hashCode()</literal> and <literal>equals()</literal> correctly on
            the component class.
        </para>
    </section>

    <section xml:id="components-compositeid" revision="1">
        <title>Components as composite identifiers</title>

        <para>
            You can use a component as an identifier of an entity class. Your component
            class must satisfy certain requirements:
        </para>

        <itemizedlist spacing="compact">
            <listitem>
                <para>
                    It must implement <literal>java.io.Serializable</literal>.
                </para>
            </listitem>
            <listitem>
                <para>
                    It must re-implement <literal>equals()</literal> and
                    <literal>hashCode()</literal> consistently with the database's
                    notion of composite key equality.
                </para>
            </listitem>
        </itemizedlist>

	<note>
	<title>Note</title>
        <para>
            In Hibernate, although the second requirement is not an absolutely hard
            requirement of Hibernate, it is recommended.
        </para>
	</note>

	<para>
            You cannot use an <literal>IdentifierGenerator</literal> to generate composite keys.
            Instead the application must assign its own identifiers.
        </para>

        <para>
            Use the <literal>&lt;composite-id&gt;</literal> tag, with nested
            <literal>&lt;key-property&gt;</literal> elements, in place of the usual
            <literal>&lt;id&gt;</literal> declaration. For example, the
            <literal>OrderLine</literal> class has a primary key that depends upon
            the (composite) primary key of <literal>Order</literal>.
        </para>

        <programlisting role="XML"><![CDATA[<class name="OrderLine">

    <composite-id name="id" class="OrderLineId">
        <key-property name="lineId"/>
        <key-property name="orderId"/>
        <key-property name="customerId"/>
    </composite-id>

    <property name="name"/>

    <many-to-one name="order" class="Order"
            insert="false" update="false">
        <column name="orderId"/>
        <column name="customerId"/>
    </many-to-one>
    ....

</class>]]></programlisting>

        <para>
            Any foreign keys referencing the <literal>OrderLine</literal> table are now
            composite. Declare this in your mappings for other classes. An association
            to <literal>OrderLine</literal> is mapped like this:
        </para>

        <programlisting role="XML"><![CDATA[<many-to-one name="orderLine" class="OrderLine">
<!-- the "class" attribute is optional, as usual -->
    <column name="lineId"/>
    <column name="orderId"/>
    <column name="customerId"/>
</many-to-one>]]></programlisting>

        <tip>
            <para>
                The <literal>column</literal> element is an alternative to the
                <literal>column</literal> attribute everywhere.  Using the
                <literal>column</literal> element just gives more declaration
                options, which are mostly useful when utilizing
                <literal>hbm2ddl</literal>
            </para>
        </tip>

        <para>
            A <literal>many-to-many</literal> association to <literal>OrderLine</literal> also
            uses the composite foreign key:
        </para>

    <programlisting role="XML"><![CDATA[<set name="undeliveredOrderLines">
    <key column name="warehouseId"/>
    <many-to-many class="OrderLine">
        <column name="lineId"/>
        <column name="orderId"/>
        <column name="customerId"/>
    </many-to-many>
</set>]]></programlisting>

        <para>
            The collection of <literal>OrderLine</literal>s in <literal>Order</literal> would
            use:
        </para>

    <programlisting role="XML"><![CDATA[<set name="orderLines" inverse="true">
    <key>
        <column name="orderId"/>
        <column name="customerId"/>
    </key>
    <one-to-many class="OrderLine"/>
</set>]]></programlisting>

        <para>
            The <literal>&lt;one-to-many&gt;</literal> element declares no columns.
        </para>

        <para>
            If <literal>OrderLine</literal> itself owns a collection, it also has a composite
            foreign key.
        </para>

        <programlisting role="XML"><![CDATA[<class name="OrderLine">
    ....
    ....
    <list name="deliveryAttempts">
        <key>   <!-- a collection inherits the composite key type -->
            <column name="lineId"/>
            <column name="orderId"/>
            <column name="customerId"/>
        </key>
        <list-index column="attemptId" base="1"/>
        <composite-element class="DeliveryAttempt">
            ...
        </composite-element>
    </set>
</class>]]></programlisting>

    </section>

    <section xml:id="components-dynamic" revision="1">
        <title>Dynamic components</title>

        <para>
            You can also map a property of type <literal>Map</literal>:
        </para>

    <programlisting role="XML"><![CDATA[<dynamic-component name="userAttributes">
    <property name="foo" column="FOO" type="string"/>
    <property name="bar" column="BAR" type="integer"/>
    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
</dynamic-component>]]></programlisting>

        <para>
            The semantics of a <literal>&lt;dynamic-component&gt;</literal> mapping are identical
            to <literal>&lt;component&gt;</literal>. The advantage of this kind of mapping is
            the ability to determine the actual properties of the bean at deployment time just
            by editing the mapping document. Runtime manipulation of the mapping document is
            also possible, using a DOM parser. You can also access, and change, Hibernate's
            configuration-time metamodel via the <literal>Configuration</literal> object.
        </para>

    </section>

</chapter>
