1
<?xml version='1.0' encoding="UTF-8"?>
3
~ Hibernate, Relational Persistence for Idiomatic Java
5
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
6
~ indicated by the @author tags or express copyright attribution
7
~ statements applied by the authors. All third-party contributions are
8
~ distributed under license by Red Hat Middleware LLC.
10
~ This copyrighted material is made available to anyone wishing to use, modify,
11
~ copy, or redistribute it subject to the terms and conditions of the GNU
12
~ Lesser General Public License, as published by the Free Software Foundation.
14
~ This program is distributed in the hope that it will be useful,
15
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
19
~ You should have received a copy of the GNU Lesser General Public License
20
~ along with this distribution; if not, write to:
21
~ Free Software Foundation, Inc.
22
~ 51 Franklin Street, Fifth Floor
23
~ Boston, MA 02110-1301 USA
26
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
28
<chapter id="example-parentchild">
29
<title>Example: Parent/Child</title>
32
One of the first things that new users want to do with Hibernate is to model a parent/child type
33
relationship. There are two different approaches to this. The most convenient
34
approach, especially for new users, is to model both <literal>Parent</literal> and <literal>Child</literal>
35
as entity classes with a <literal><one-to-many></literal> association from <literal>Parent</literal>
36
to <literal>Child</literal>. The alternative approach is to declare the <literal>Child</literal> as a
37
<literal><composite-element></literal>. The default semantics of a one-to-many
38
association in Hibernate are much less close to the usual semantics of a parent/child relationship than
39
those of a composite element mapping. We will explain how to use a <emphasis>bidirectional one-to-many
40
association with cascades</emphasis> to model a parent/child relationship efficiently and elegantly.
44
<sect1 id="example-parentchild-collections">
45
<title>A note about collections</title>
48
Hibernate collections are considered to be a logical part of their owning entity and not of the
49
contained entities. Be aware that this is a critical distinction that has the following consequences:
55
When you remove/add an object from/to a collection, the version number of the collection owner
61
If an object that was removed from a collection is an instance of a value type (e.g. a composite
62
element), that object will cease to be persistent and its state will be completely removed from
63
the database. Likewise, adding a value type instance to the collection will cause its state to be
64
immediately persistent.
69
Conversely, if an entity is removed from a collection (a one-to-many or many-to-many
70
association), it will not be deleted by default. This behavior is completely consistent; a
71
change to the internal state of another entity should not cause the associated entity to vanish.
72
Likewise, adding an entity to a collection does not cause that entity to become persistent, by
79
Adding an entity to a collection, by default, merely creates a link between
80
the two entities. Removing the entity will remove the link. This is appropriate for all sorts of cases.
81
However, it is not appropriate in the case of a parent/child relationship. In this case, the life of the
82
child is bound to the life cycle of the parent.
87
<sect1 id="example-parentchild-bidir">
88
<title>Bidirectional one-to-many</title>
91
Suppose we start with a simple <literal><one-to-many></literal> association from
92
<literal>Parent</literal> to <literal>Child</literal>.
95
<programlisting><![CDATA[<set name="children">
96
<key column="parent_id"/>
97
<one-to-many class="Child"/>
98
</set>]]></programlisting>
101
If we were to execute the following code:
104
<programlisting><![CDATA[Parent p = .....;
105
Child c = new Child();
106
p.getChildren().add(c);
108
session.flush();]]></programlisting>
111
Hibernate would issue two SQL statements:
116
<para>an <literal>INSERT</literal> to create the record for <literal>c</literal></para>
120
an <literal>UPDATE</literal> to create the link from <literal>p</literal> to
127
This is not only inefficient, but also violates any <literal>NOT NULL</literal> constraint on the
128
<literal>parent_id</literal> column. You can fix the nullability constraint violation by specifying
129
<literal>not-null="true"</literal> in the collection mapping:
132
<programlisting><![CDATA[<set name="children">
133
<key column="parent_id" not-null="true"/>
134
<one-to-many class="Child"/>
135
</set>]]></programlisting>
138
However, this is not the recommended solution.
141
The underlying cause of this behavior is that the link (the foreign key <literal>parent_id</literal>)
142
from <literal>p</literal> to <literal>c</literal> is not considered part of the state of the
143
<literal>Child</literal> object and is therefore not created in the <literal>INSERT</literal>. The
144
solution is to make the link part of the <literal>Child</literal> mapping.
147
<programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
150
You also need to add the <literal>parent</literal> property to the <literal>Child</literal> class.
154
Now that the <literal>Child</literal> entity is managing the state of the link, we tell the collection
155
not to update the link. We use the <literal>inverse</literal> attribute to do this:
158
<programlisting><![CDATA[<set name="children" inverse="true">
159
<key column="parent_id"/>
160
<one-to-many class="Child"/>
161
</set>]]></programlisting>
164
The following code would be used to add a new <literal>Child</literal>:
167
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
168
Child c = new Child();
170
p.getChildren().add(c);
172
session.flush();]]></programlisting>
175
Only one SQL <literal>INSERT</literal> would now be issued.
179
You could also create an <literal>addChild()</literal> method of
180
<literal>Parent</literal>.
183
<programlisting><![CDATA[public void addChild(Child c) {
186
}]]></programlisting>
189
The code to add a <literal>Child</literal> looks like this:
192
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
193
Child c = new Child();
196
session.flush();]]></programlisting>
200
<sect1 id="example-parentchild-cascades">
201
<title>Cascading life cycle</title>
204
You can address the frustrations of the explicit call to <literal>save()</literal> by
208
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
209
<key column="parent_id"/>
210
<one-to-many class="Child"/>
211
</set>]]></programlisting>
214
This simplifies the code above to:
217
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
218
Child c = new Child();
220
session.flush();]]></programlisting>
223
Similarly, we do not need to iterate over the children when saving or deleting a <literal>Parent</literal>.
224
The following removes <literal>p</literal> and all its children from the database.
227
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
229
session.flush();]]></programlisting>
232
However, the following code:
235
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
236
Child c = (Child) p.getChildren().iterator().next();
237
p.getChildren().remove(c);
239
session.flush();]]></programlisting>
242
will not remove <literal>c</literal> from the database. In this case, it will only remove the link to <literal>p</literal>
243
and cause a <literal>NOT NULL</literal> constraint violation. You need to explicitly
244
<literal>delete()</literal> the <literal>Child</literal>.
247
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
248
Child c = (Child) p.getChildren().iterator().next();
249
p.getChildren().remove(c);
251
session.flush();]]></programlisting>
254
In our case, a <literal>Child</literal> cannot exist without its parent. So if we remove
255
a <literal>Child</literal> from the collection, we do want it to be deleted. To do this, we must
256
use <literal>cascade="all-delete-orphan"</literal>.
259
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
260
<key column="parent_id"/>
261
<one-to-many class="Child"/>
262
</set>]]></programlisting>
265
Even though the collection mapping specifies <literal>inverse="true"</literal>, cascades are
266
still processed by iterating the collection elements. If you need an object be saved,
267
deleted or updated by cascade, you must add it to the collection. It is not enough to simply call
268
<literal>setParent()</literal>.
273
<sect1 id="example-parentchild-update">
274
<title>Cascades and <literal>unsaved-value</literal></title>
277
Suppose we loaded up a <literal>Parent</literal> in one <literal>Session</literal>, made some changes
278
in a UI action and wanted to persist these changes in a new session by calling <literal>update()</literal>.
279
The <literal>Parent</literal> will contain a collection of children and, since the cascading update is enabled,
280
Hibernate needs to know which children are newly instantiated and which represent existing rows in the
281
database. We will also assume that both <literal>Parent</literal> and <literal>Child</literal> have generated
282
identifier properties of type <literal>Long</literal>. Hibernate will use the identifier and
283
version/timestamp property value to determine which of the children are new. (See
284
<xref linkend="objectstate-saveorupdate"/>.) <emphasis>In Hibernate3, it is no longer necessary to specify
285
an <literal>unsaved-value</literal> explicitly.</emphasis>
289
The following code will update <literal>parent</literal> and <literal>child</literal> and insert
290
<literal>newChild</literal>:
293
<programlisting><![CDATA[//parent and child were both loaded in a previous session
294
parent.addChild(child);
295
Child newChild = new Child();
296
parent.addChild(newChild);
297
session.update(parent);
298
session.flush();]]></programlisting>
301
This may be suitable for the case of a generated identifier, but what about assigned identifiers
302
and composite identifiers? This is more difficult, since Hibernate cannot use the identifier property to
303
distinguish between a newly instantiated object, with an identifier assigned by the user, and an
304
object loaded in a previous session. In this case, Hibernate will either use the timestamp or version
305
property, or will actually query the second-level cache or, worst case, the database, to see if the
311
There is one further possibility. The <literal>Interceptor</literal> method named
312
<literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
313
newly instantiated objects. For example, you could define a base class for your persistent classes.
316
<programlisting><![CDATA[public class Persistent {
317
private boolean _saved = false;
318
public void onSave() {
321
public void onLoad() {
325
public boolean isSaved() {
328
}]]></programlisting>
331
(The <literal>saved</literal> property is non-persistent.)
332
Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
333
and <literal>onSave()</literal> as follows.
336
<programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
337
if (entity instanceof Persistent) {
338
return new Boolean( !( (Persistent) entity ).isSaved() );
345
public boolean onLoad(Object entity,
348
String[] propertyNames,
351
if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
355
public boolean onSave(Object entity,
358
String[] propertyNames,
361
if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
363
}]]></programlisting>
366
Do not worry; in Hibernate3 you do not need to write any of this kind of code if you do not want to.
371
<sect1 id="example-parentchild-conclusion">
372
<title>Conclusion</title>
375
The sections we have just covered can be a bit confusing. However, in practice,
376
it all works out nicely. Most Hibernate applications use the parent/child pattern in many places.
380
We mentioned an alternative in the first paragraph. None of the above issues exist in the case of
381
<literal><composite-element></literal> mappings, which have exactly the semantics of a parent/child
382
relationship. Unfortunately, there are two big limitations with composite element classes: composite elements
383
cannot own collections and they should not be the child of any entity other than the unique parent.