Many small improvements

git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@5366 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Christian Bauer 2005-01-27 16:56:36 +00:00
parent 7ca1999a26
commit 53343571c9
3 changed files with 95 additions and 59 deletions

View File

@ -1,7 +1,7 @@
<chapter id="collections">
<title>Collection Mapping</title>
<sect1 id="collections-persistent" revision="1">
<sect1 id="collections-persistent" revision="2">
<title>Persistent Collections</title>
<para>
@ -27,20 +27,25 @@
<para>
Now the caveat: persistent collections do not retain any extra semantics added by the class
implementing the collection interface (eg. iteration order of a <literal>LinkedHashSet</literal>).
The persistent collections actually behave like
The Java type of a property holding a collection must be the interface type: <literal>Map</literal>,
<literal>Set</literal>, <literal>List</literal>, or simply <literal>Collection</literal>; never
<literal>HashMap</literal>, <literal>TreeSet</literal> or <literal>ArrayList</literal>. This
restriction exists because, when you're not looking, Hibernate sneakily replaces your instances
of <literal>Map</literal>, <literal>Set</literal> and <literal>List</literal> with instances
of its own persistent implementations of <literal>Map</literal>, <literal>Set</literal>, or
<literal>List</literal>. (So also be careful when using <literal>==</literal> on your collections.)
</para>
<para>
You may therefore initialize a collection in your class with whatever implementation
you find compatible. The persistent collections injected by Hibernate behave like
<literal>HashMap</literal>,
<literal>HashSet</literal>,
<literal>TreeMap</literal>,
<literal>TreeSet</literal> and
<literal>ArrayList</literal>
respectively. Furthermore, the Java type of a property holding a collection must be
the interface type (ie. <literal>Map</literal>, <literal>Set</literal> or
<literal>List</literal>; never <literal>HashMap</literal>, <literal>TreeSet</literal> or
<literal>ArrayList</literal>). This restriction exists because, when you're not looking,
Hibernate sneakily replaces your instances of <literal>Map</literal>, <literal>Set</literal>
and <literal>List</literal> with instances of its own persistent implementations of
<literal>Map</literal>, <literal>Set</literal> or <literal>List</literal>. (So also be careful
when using <literal>==</literal> on your collections.)
respectively. Of course, this depends on the mapping style you chose (ie. ordered or
not, preserving position of elements, allowing duplicates, etc).
</para>
<programlisting><![CDATA[Cat cat = new DomesticCat();
@ -50,12 +55,12 @@ Set kittens = new HashSet();
kittens.add(kitten);
cat.setKittens(kittens);
session.save(cat);
kittens = cat.getKittens(); //Okay, kittens collection is a Set
(HashSet) cat.getKittens(); //Error!]]></programlisting>
kittens = cat.getKittens(); // Okay, kittens collection is a Set
(HashSet) cat.getKittens(); // Error!]]></programlisting>
<para>
Collections obey the usual rules for value types: no shared
references, created and deleted along with containing entity. Due to the underlying
Collections (not the contents) obey the usual rules for value types: no shared
references, created and deleted along with the owning entity. Due to the underlying
relational model, they do not support null value semantics; Hibernate does not
distinguish between a null collection reference and an empty collection.
</para>
@ -73,36 +78,41 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
<para>
Collection instances are distinguished in the database by a foreign key to
the owning entity. This foreign key is referred to as the
<emphasis>collection key </emphasis>. The collection key is mapped by
the <literal>&lt;key&gt;</literal> element. If you have a foreign-key constraint
set in the database, and have chosen the <literal>ON DELETE CASCADE</literal>
option, always use the <literal>on-delete</literal> attribute on your
<literal>&lt;key&gt;</literal> mappings:
<emphasis>collection key </emphasis>, on the table holding the collection elements.
The collection key is mapped by the <literal>&lt;key&gt;</literal> element. If you
have a foreign-key constraint set in the database, and have chosen the
<literal>ON DELETE CASCADE</literal> option, always use the
<literal>on-delete</literal> attribute on your <literal>&lt;key&gt;</literal>
mappings:
</para>
<programlisting><![CDATA[<key column="CHILD_ID" on-delete="cascade"/>]]></programlisting>
<para>
Collections may contain almost any other Hibernate type, including all basic types,
custom types, entity types and components. This is an important definition: An object
in a collection can either be handled with "pass by value" semantics (it therefore
fully depends on the collection owner) or it can be a reference to another entity
with an own lifecycle. Collections may not contain other collections. The contained type
custom types, components, and of course, references to other entities. This is an
important definition: An object in a collection can either be handled with "pass by
value" semantics (it therefore fully depends on the collection owner) or it can be a
reference to another entity, with its own lifecycle. In this case, only the "link"
between two objects is stored in the collection (non-Java developers call these links
"pointers"). Collections may not contain other collections. The contained type
is referred to as the <emphasis>collection element type</emphasis>. Collection elements
are mapped by <literal>&lt;element&gt;</literal>, <literal>&lt;composite-element&gt;</literal>,
<literal>&lt;one-to-many&gt;</literal>, <literal>&lt;many-to-many&gt;</literal> or
<literal>&lt;many-to-any&gt;</literal>. The first two map elements with value semantics,
the other three are used to map entity associations.
or in the case of entity references, with <literal>&lt;one-to-many&gt;</literal>,
<literal>&lt;many-to-many&gt;</literal>, or <literal>&lt;many-to-any&gt;</literal>.
The first two map elements with value semantics, the other three are used to map
entity associations.
</para>
<para>
All collection types except <literal>Set</literal> and bag have an <emphasis>index
</emphasis> column - a column that maps to an array or <literal>List</literal> index or
<literal>Map</literal> key. The index of a <literal>Map</literal> may be of any
basic type, an entity type or even a composite type (it may not be a collection). The
index of an array or list is always of type <literal>integer</literal>. Indexes are
mapped using <literal>&lt;index&gt;</literal>, <literal>&lt;index-many-to-many&gt;</literal>,
<literal>&lt;composite-index&gt;</literal> or <literal>&lt;index-many-to-any&gt;</literal>.
All collection mappings, except those with set and bag semantics, need an
<emphasis>index</emphasis> column in the collection table - a column that maps to an
array index, or <literal>List</literal> index, or <literal>Map</literal> key. The
index of a <literal>Map</literal> may be of any basic type, it may be an entity reference,
or even a composite type (it may not be a collection). The index of an array or list is
always of type <literal>integer</literal>. Indexes are mapped using
<literal>&lt;index&gt;</literal>, <literal>&lt;index-many-to-many&gt;</literal>,
<literal>&lt;composite-index&gt;</literal>, or <literal>&lt;index-many-to-any&gt;</literal>.
</para>
<para>
@ -270,7 +280,7 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
</sect1>
<sect1 id="collections-ofvalues">
<sect1 id="collections-ofvalues" revision="1">
<title>Collections of Values and Many-To-Many Associations</title>
<para>
@ -390,9 +400,8 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
</programlistingco>
<para>
A collection of entities with its own table corresponds to the relational notion
of <emphasis>many-to-many association</emphasis>. A many to many association is the
most natural mapping of a Java collection but is not usually the best relational model.
A collection of entity references, where the references are held in a separate table
corresponds to the relational notion of <emphasis>many-to-many association</emphasis>.
</para>
<programlistingco>
@ -404,7 +413,7 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
<programlisting><![CDATA[<many-to-many
column="column_name"
class="ClassName"
outer-join="true|false|auto"
fetch="select|join"
/>]]></programlisting>
<calloutlist>
<callout arearefs="manytomany1">
@ -419,9 +428,13 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
</callout>
<callout arearefs="manytomany3">
<para>
<literal>outer-join</literal> (optional - defaults to <literal>auto</literal>):
enables outer-join fetching for this association when
<literal>hibernate.use_outer_join</literal> is set.
<literal>fetch</literal> (optional - defaults to <literal>join</literal>):
enables outer-join or sequential select fetching for this association. This
is a special case, for full eager fetching (in a single <literal>SELECT</literal>)
of an entity and its many-to-many relationships to other entities, you would
enable <literal>join</literal> fetching not only of the collection itself,
but also with this attribute on the <literal>&lt;many-to-many&gt;</literal>
nested element.
</para>
</callout>
</calloutlist>
@ -566,7 +579,7 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
</sect1>
<sect1 id="collections-sorted" revision="1">
<sect1 id="collections-sorted" revision="2">
<title>Sorted Collections</title>
<para>
@ -605,7 +618,7 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
memory.
</para>
<programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="name asc">
<programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
<key column="person"/>
<element column="name" type="string"/>
</set>
@ -678,7 +691,7 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
</sect1>
<sect1 id="collections-bidirectional">
<sect1 id="collections-bidirectional" revision="1">
<title>Bidirectional Associations</title>
<para>
@ -716,9 +729,13 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
<para>
You may specify a bidirectional many-to-many association simply by mapping two
many-to-many associations to the same database table and declaring one end as
<emphasis>inverse</emphasis> (which one is your choice). Here's an example of
a bidirectional many-to-many association from a class back to <emphasis>itself</emphasis>
(each category can have many items and each item can be in many categories):
<emphasis>inverse</emphasis> (which one is your choice, but it can not be an
indexed collection).
</para>
<para>
Here's an example of a bidirectional many-to-many association; each category can
have many items and each item can be in many categories:
</para>
<programlisting><![CDATA[<class name="org.hibernate.auction.Category">
@ -753,18 +770,18 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
category.getItems().add(item); // The category now "knows" about the relationship
item.getCategories().add(category); // The item now "knows" about the relationship
session.update(item); // No effect, nothing will be saved!
session.update(category); // The relationship will be saved]]></programlisting>
session.create(item); // The relationship won't be saved!
session.create(category); // The relationship will be saved]]></programlisting>
<para>
The non-inverse side is used to save the in-memory representation to the database.
We would get an unneccessary INSERT/UPDATE and probably even a foreign key violation
if both would trigger changes! The same is of course also true for bidirectional
one-to-many associations.
if both would trigger changes!
</para>
<para>
You may map a bidirectional one-to-many association by mapping a one-to-many association
The same is of course also true for bidirectional one-to-many associations. You may
map a bidirectional one-to-many association by mapping a one-to-many association
to the same table column(s) as a many-to-one association and declaring the many-valued
end <literal>inverse="true"</literal>.
</para>

View File

@ -10,8 +10,8 @@
<title>Dependent objects</title>
<para>
A component is a contained object that is persisted as a value type, not an entity.
The term "component" refers to the object-oriented notion of composition
A component is a contained object that is persisted as a value type, not an entity
reference. The term "component" refers to the object-oriented notion of composition
(not to architecture-level components). For example, you might model a person like this:
</para>
@ -97,10 +97,12 @@
</para>
<para>
Like all value types, components do not support shared references. 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 should be okay for most purposes.
Like all 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 ojects, 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 should
be okay for most purposes.
</para>
<para>
@ -131,7 +133,7 @@
</sect1>
<sect1 id="components-incollections">
<sect1 id="components-incollections" revision="1">
<title>Collections of dependent objects</title>
<para>
@ -202,6 +204,14 @@
</set>
</class>]]></programlisting>
<para>
Of course, there can't be a reference to the purchae on the other side, for
bidirectional association navigation. Remember that components are value types and
don't allow shared references. A single <literal>Purchase</literal> can be in the
set of an <literal>Order</literal>, but it can't be referenced by the <literal>Item</literal>
at the same time.
</para>
<para>Even ternary (or quaternary, etc) associations are possible:</para>
<programlisting><![CDATA[<class name="eg.Order" .... >
@ -268,6 +278,10 @@
previous session.
</para>
<para>
TODO: document new auto-detect features for assigned IDs in H3
</para>
<para>
So, if you wish to use transitive reattachment (you don't have to), you must
either implement <literal>Interceptor.isUnsaved()</literal> or define the

View File

@ -4,6 +4,11 @@
<sect1 id="inheritance-strategies" revision="2">
<title>The Three Strategies</title>
<para>
TODO: While this is all still supported, many new features would require
a rewrite of this whole chapter
</para>
<para>
Hibernate supports the three basic inheritance mapping strategies.
</para>