6.2. Collection mappings

Tip

There are quite a range of mappings that can be generated for collections, covering many common relational models. We suggest you experiment with the schema generation tool to get a feeling for how various mapping declarations translate to database tables.

The Hibernate mapping element used for mapping a collection depends upon the type of the interface. For example, a <set> element is used for mapping properties of type Set.

<class name="Product">
    <id name="serialNumber" column="productSerialNumber"/>
    <set name="parts">
        <key column="productSerialNumber" not-null="true"/>
        <one-to-many class="Part"/>
    </set>
</class>

Apart from <set>, there is also <list>, <map>, <bag>, <array> and <primitive-array> mapping elements. The <map> element is representative:

<map
    name="propertyName"                                         (1)
    table="table_name"                                          (2)
    schema="schema_name"                                        (3)
    lazy="true|extra|false"                                     (4)
    inverse="true|false"                                        (5)
    cascade="all|none|save-update|delete|all-delete-orphan|delet(6)e-orphan"
    sort="unsorted|natural|comparatorClass"                     (7)
    order-by="column_name asc|desc"                             (8)
    where="arbitrary sql where condition"                       (9)
    fetch="join|select|subselect"                               (10)
    batch-size="N"                                              (11)
    access="field|property|ClassName"                           (12)
    optimistic-lock="true|false"                                (13)
    mutable="true|false"                                        (14)
    node="element-name|."
    embed-xml="true|false"
>

    <key .... />
    <map-key .... />
    <element .... />
</map>
(1)

name the collection property name

(2)

table (optional - defaults to property name) the name of the collection table (not used for one-to-many associations)

(3)

schema (optional) the name of a table schema to override the schema declared on the root element

(4)

lazy (optional - defaults to true) may be used to disable lazy fetching and specify that the association is always eagerly fetched, or to enable "extra-lazy" fetching where most operations do not initialize the collection (suitable for very large collections)

(5)

inverse (optional - defaults to false) mark this collection as the "inverse" end of a bidirectional association

(6)

cascade (optional - defaults to none) enable operations to cascade to child entities

(7)

sort (optional) specify a sorted collection with natural sort order, or a given comparator class

(8)

order-by (optional, JDK1.4 only) specify a table column (or columns) that define the iteration order of the Map, Set or bag, together with an optional asc or desc

(9)

where (optional) specify an arbitrary SQL WHERE condition to be used when retrieving or removing the collection (useful if the collection should contain only a subset of the available data)

(10)

fetch (optional, defaults to select) Choose between outer-join fetching, fetching by sequential select, and fetching by sequential subselect.

(11)

batch-size (optional, defaults to 1) specify a "batch size" for lazily fetching instances of this collection.

(12)

access (optional - defaults to property): The strategy Hibernate should use for accessing the collection property value.

(13)

optimistic-lock (optional - defaults to true): Species that changes to the state of the collection results in increment of the owning entity's version. (For one to many associations, it is often reasonable to disable this setting.)

(14)

mutable (optional - defaults to true): A value of false specifies that the elements of the collection never change (a minor performance optimization in some cases).

6.2.1. Collection foreign keys

Collection instances are distinguished in the database by the foreign key of the entity that owns the collection. This foreign key is referred to as the collection key column (or columns) of the collection table. The collection key column is mapped by the <key> element.

There may be a nullability constraint on the foreign key column. For most collections, this is implied. For unidirectional one to many associations, the foreign key column is nullable by default, so you might need to specify not-null="true".

<key column="productSerialNumber" not-null="true"/>

The foreign key constraint may use ON DELETE CASCADE.

<key column="productSerialNumber" on-delete="cascade"/>

See the previous chapter for a full definition of the <key> element.

6.2.2. Collection elements

Collections may contain almost any other Hibernate type, including all basic types, custom types, components, and of course, references to other entities. This is an important distinction: an object in a collection might be handled with "value" semantics (its life cycle fully depends on the collection owner) or it might be a reference to another entity, with its own life cycle. In the latter case, only the "link" between the two objects is considered to be state held by the collection.

The contained type is referred to as the collection element type. Collection elements are mapped by <element> or <composite-element>, or in the case of entity references, with <one-to-many> or <many-to-many>. The first two map elements with value semantics, the next two are used to map entity associations.

6.2.3. Indexed collections

All collection mappings, except those with set and bag semantics, need an index column in the collection table - a column that maps to an array index, or List index, or Map key. The index of a Map may be of any basic type, mapped with <map-key>, it may be an entity reference mapped with <map-key-many-to-many>, or it may be a composite type, mapped with <composite-map-key>. The index of an array or list is always of type integer and is mapped using the <list-index> element. The mapped column contains sequential integers (numbered from zero, by default).

<list-index 
        column="column_name"                (1)
        base="0|1|..."/>
(1)

column_name (required): The name of the column holding the collection index values.

(1)

base (optional, defaults to 0): The value of the index column that corresponds to the first element of the list or array.

<map-key 
        column="column_name"                (1)
        formula="any SQL expression"        (2)
        type="type_name"                    (3)
        node="@attribute-name"
        length="N"/>
(1)

column (optional): The name of the column holding the collection index values.

(2)

formula (optional): A SQL formula used to evaluate the key of the map.

(3)

type (reguired): The type of the map keys.

<map-key-many-to-many
        column="column_name"                (1)
        formula="any SQL expression"        (2)(3)
        class="ClassName"
/>
(1)

column (optional): The name of the foreign key column for the collection index values.

(2)

formula (optional): A SQL formula used to evaluate the foreign key of the map key.

(3)

class (required): The entity class used as the map key.

If your table doesn't have an index column, and you still wish to use List as the property type, you should map the property as a Hibernate <bag>. A bag does not retain its order when it is retrieved from the database, but it may be optionally sorted or ordered.

6.2.4. Collections of values and many-to-many associations

Any collection of values or many-to-many association requires a dedicated collection table with a foreign key column or columns, collection element column or columns and possibly an index column or columns.

For a collection of values, we use the <element> tag.

<element
        column="column_name"                     (1)
        formula="any SQL expression"             (2)
        type="typename"                          (3)
        length="L"
        precision="P"
        scale="S"
        not-null="true|false"
        unique="true|false"
        node="element-name"
/>
(1)

column (optional): The name of the column holding the collection element values.

(2)

formula (optional): An SQL formula used to evaluate the element.

(3)

type (required): The type of the collection element.

A many-to-many association is specified using the <many-to-many> element.

<many-to-many
        column="column_name"                               (1)
        formula="any SQL expression"                       (2)
        class="ClassName"                                  (3)
        fetch="select|join"                                (4)
        unique="true|false"                                (5)
        not-found="ignore|exception"                       (6)
        entity-name="EntityName"                           (7)
        property-ref="propertyNameFromAssociatedClass"     (8)
        node="element-name"
        embed-xml="true|false"
    />
(1)

column (optional): The name of the element foreign key column.

(2)

formula (optional): An SQL formula used to evaluate the element foreign key value.

(3)

class (required): The name of the associated class.

(4)

fetch (optional - defaults to join): enables outer-join or sequential select fetching for this association. This is a special case; for full eager fetching (in a single SELECT) of an entity and its many-to-many relationships to other entities, you would enable join fetching not only of the collection itself, but also with this attribute on the <many-to-many> nested element.

(5)

unique (optional): Enable the DDL generation of a unique constraint for the foreign-key column. This makes the association multiplicity effectively one to many.

(6)

not-found (optional - defaults to exception): Specifies how foreign keys that reference missing rows will be handled: ignore will treat a missing row as a null association.

(7)

entity-name (optional): The entity name of the associated class, as an alternative to class.

(8)

property-ref: (optional) The name of a property of the associated class that is joined to this foreign key. If not specified, the primary key of the associated class is used.

Some examples, first, a set of strings:

<set name="names" table="person_names">
    <key column="person_id"/>
    <element column="person_name" type="string"/>
</set>

A bag containing integers (with an iteration order determined by the order-by attribute):

<bag name="sizes" 
        table="item_sizes" 
        order-by="size asc">
    <key column="item_id"/>
    <element column="size" type="integer"/>
</bag>

An array of entities - in this case, a many to many association:

<array name="addresses" 
        table="PersonAddress" 
        cascade="persist">
    <key column="personId"/>
    <list-index column="sortOrder"/>
    <many-to-many column="addressId" class="Address"/>
</array>

A map from string indices to dates:

<map name="holidays" 
        table="holidays" 
        schema="dbo" 
        order-by="hol_name asc">
    <key column="id"/>
    <map-key column="hol_name" type="string"/>
    <element column="hol_date" type="date"/>
</map>

A list of components (discussed in the next chapter):

<list name="carComponents" 
        table="CarComponents">
    <key column="carId"/>
    <list-index column="sortOrder"/>
    <composite-element class="CarComponent">
        <property name="price"/>
        <property name="type"/>
        <property name="serialNumber" column="serialNum"/>
    </composite-element>
</list>

6.2.5. One-to-many associations

A one to many association links the tables of two classes via a foreign key, with no intervening collection table. This mapping loses certain semantics of normal Java collections:

  • An instance of the contained entity class may not belong to more than one instance of the collection

  • An instance of the contained entity class may not appear at more than one value of the collection index

An association from Product to Part requires existence of a foreign key column and possibly an index column to the Part table. A <one-to-many> tag indicates that this is a one to many association.

<one-to-many 
        class="ClassName"                                  (1)
        not-found="ignore|exception"                       (2)
        entity-name="EntityName"                           (3)
        node="element-name"
        embed-xml="true|false"
    />
(1)

class (required): The name of the associated class.

(2)

not-found (optional - defaults to exception): Specifies how cached identifiers that reference missing rows will be handled: ignore will treat a missing row as a null association.

(3)

entity-name (optional): The entity name of the associated class, as an alternative to class.

Notice that the <one-to-many> element does not need to declare any columns. Nor is it necessary to specify the table name anywhere.

Very important note: If the foreign key column of a <one-to-many> association is declared NOT NULL, you must declare the <key> mapping not-null="true" or use a bidirectional association with the collection mapping marked inverse="true". See the discussion of bidirectional associations later in this chapter.

This example shows a map of Part entities by name (where partName is a persistent property of Part). Notice the use of a formula-based index.

<map name="parts"
        cascade="all">
    <key column="productId" not-null="true"/>
    <map-key formula="partName"/>
    <one-to-many class="Part"/>
</map>