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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
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.
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|..."/>
|
|
|
|
<map-key column="column_name" (1) formula="any SQL expression" (2) type="type_name" (3) node="@attribute-name" length="N"/>
|
|
|
|
|
|
<map-key-many-to-many column="column_name" (1) formula="any SQL expression" (2)(3) class="ClassName" />
|
|
|
|
|
|
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.
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" />
|
|
|
|
|
|
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" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>
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" />
|
|
|
|
|
|
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>