Author: hardy.ferentschik
Date: 2010-07-14 15:31:59 -0400 (Wed, 14 Jul 2010)
New Revision: 19954
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml
Log:
HHH-5379 Added CascadeTypes for annotations
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml
===================================================================
---
core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml 2010-07-14
18:59:15 UTC (rev 19953)
+++
core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml 2010-07-14
19:31:59 UTC (rev 19954)
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
@@ -22,273 +22,237 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM
"../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
-
]>
-
<chapter id="objectstate">
- <title>Working with objects</title>
+ <title>Working with objects</title>
- <para>
- Hibernate is a full object/relational mapping solution that not only shields
- the developer from the details of the underlying database management
- system, but also offers <emphasis>state management</emphasis> of
objects. This is,
- contrary to the management of SQL <literal>statements</literal> in
common JDBC/SQL
- persistence layers, a natural object-oriented view of persistence in Java
- applications.
- </para>
+ <para>Hibernate is a full object/relational mapping solution that not only
+ shields the developer from the details of the underlying database management
+ system, but also offers <emphasis>state management</emphasis> of objects.
+ This is, contrary to the management of SQL <literal>statements</literal>
in
+ common JDBC/SQL persistence layers, a natural object-oriented view of
+ persistence in Java applications.</para>
- <para>
- In other words, Hibernate application developers should always think about the
- <emphasis>state</emphasis> of their objects, and not necessarily
about the
- execution of SQL statements. This part is taken care of by Hibernate and is only
- relevant for the application developer when tuning the performance of the
system.
- </para>
+ <para>In other words, Hibernate application developers should always think
+ about the <emphasis>state</emphasis> of their objects, and not necessarily
+ about the execution of SQL statements. This part is taken care of by
+ Hibernate and is only relevant for the application developer when tuning the
+ performance of the system.</para>
- <section id="objectstate-overview">
- <title>Hibernate object states</title>
+ <section id="objectstate-overview">
+ <title>Hibernate object states</title>
- <para>
- Hibernate defines and supports the following object states:
- </para>
+ <para>Hibernate defines and supports the following object states:</para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Transient</emphasis> - an object is transient
if it has just
- been instantiated using the <literal>new</literal>
operator, and it
- is not associated with a Hibernate
<literal>Session</literal>. It has no
- persistent representation in the database and no identifier value has
been
- assigned. Transient instances will be destroyed by the garbage
collector if
- the application does not hold a reference anymore. Use the Hibernate
- <literal>Session</literal> to make an object persistent
(and let Hibernate
- take care of the SQL statements that need to be executed for this
transition).
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Persistent</emphasis> - a persistent instance
has a representation
- in the database and an identifier value. It might just have been
saved or loaded,
- however, it is by definition in the scope of a
<literal>Session</literal>.
- Hibernate will detect any changes made to an object in persistent
state and
- synchronize the state with the database when the unit of work
completes.
- Developers do not execute manual
<literal>UPDATE</literal> statements, or
- <literal>DELETE</literal> statements when an object
should be made transient.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Detached</emphasis> - a detached instance is an
object that has been
- persistent, but its <literal>Session</literal> has been
closed. The reference
- to the object is still valid, of course, and the detached instance
might even
- be modified in this state. A detached instance can be reattached to a
new
- <literal>Session</literal> at a later point in time,
making it (and all the
- modifications) persistent again. This feature enables a programming
model for
- long running units of work that require user think-time. We call
them
- <emphasis>application transactions</emphasis>, i.e., a
unit of work from the
- point of view of the user.
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>Transient</emphasis> - an object is transient
if it
+ has just been instantiated using the <literal>new</literal>
operator,
+ and it is not associated with a Hibernate
<literal>Session</literal>.
+ It has no persistent representation in the database and no identifier
+ value has been assigned. Transient instances will be destroyed by the
+ garbage collector if the application does not hold a reference
+ anymore. Use the Hibernate <literal>Session</literal> to make an
+ object persistent (and let Hibernate take care of the SQL statements
+ that need to be executed for this transition).</para>
+ </listitem>
- <para>
- We will now discuss the states and state transitions (and the Hibernate
methods that
- trigger a transition) in more detail.
- </para>
+ <listitem>
+ <para><emphasis>Persistent</emphasis> - a persistent instance
has a
+ representation in the database and an identifier value. It might just
+ have been saved or loaded, however, it is by definition in the scope
+ of a <literal>Session</literal>. Hibernate will detect any changes
+ made to an object in persistent state and synchronize the state with
+ the database when the unit of work completes. Developers do not
+ execute manual <literal>UPDATE</literal> statements, or
+ <literal>DELETE</literal> statements when an object should be made
+ transient.</para>
+ </listitem>
- </section>
+ <listitem>
+ <para><emphasis>Detached</emphasis> - a detached instance is an
object
+ that has been persistent, but its <literal>Session</literal> has
been
+ closed. The reference to the object is still valid, of course, and the
+ detached instance might even be modified in this state. A detached
+ instance can be reattached to a new <literal>Session</literal> at a
+ later point in time, making it (and all the modifications) persistent
+ again. This feature enables a programming model for long running units
+ of work that require user think-time. We call them
+ <emphasis>application transactions</emphasis>, i.e., a unit of work
+ from the point of view of the user.</para>
+ </listitem>
+ </itemizedlist>
- <section id="objectstate-makingpersistent" revision="1">
- <title>Making objects persistent</title>
+ <para>We will now discuss the states and state transitions (and the
+ Hibernate methods that trigger a transition) in more detail.</para>
+ </section>
- <para>
- Newly instantiated instances of a persistent class are considered
- <emphasis>transient</emphasis> by Hibernate. We can make a
transient
- instance <emphasis>persistent</emphasis> by associating it with a
- session:
- </para>
+ <section id="objectstate-makingpersistent" revision="1">
+ <title>Making objects persistent</title>
- <programlisting role="JAVA"><![CDATA[DomesticCat fritz = new
DomesticCat();
+ <para>Newly instantiated instances of a persistent class are considered
+ <emphasis>transient</emphasis> by Hibernate. We can make a transient
+ instance <emphasis>persistent</emphasis> by associating it with a
+ session:</para>
+
+ <programlisting role="JAVA">DomesticCat fritz = new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex('M');
fritz.setName("Fritz");
-Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+Long generatedId = (Long) sess.save(fritz);</programlisting>
- <para>
- If <literal>Cat</literal> has a generated identifier, the
identifier is
- generated and assigned to the <literal>cat</literal> when
<literal>save()</literal>
- is called. If <literal>Cat</literal> has an
<literal>assigned</literal>
- identifier, or a composite key, the identifier should be assigned to
- the <literal>cat</literal> instance before calling
<literal>save()</literal>.
- You can also use <literal>persist()</literal> instead of
<literal>save()</literal>,
- with the semantics defined in the EJB3 early draft.
- </para>
+ <para>If <literal>Cat</literal> has a generated identifier, the
identifier
+ is generated and assigned to the <literal>cat</literal> when
+ <literal>save()</literal> is called. If
<literal>Cat</literal> has an
+ <literal>assigned</literal> identifier, or a composite key, the
identifier
+ should be assigned to the <literal>cat</literal> instance before calling
+ <literal>save()</literal>. You can also use
<literal>persist()</literal>
+ instead of <literal>save()</literal>, with the semantics defined in the
+ EJB3 early draft.</para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>persist()</literal> makes a transient instance
persistent.
- However, it does not guarantee that the identifier value will be
assigned to
- the persistent instance immediately, the assignment might happen at
flush time.
- <literal>persist()</literal> also guarantees that it will
not execute an
- <literal>INSERT</literal> statement if it is called
outside of transaction
- boundaries. This is useful in long-running conversations with an
extended
- Session/persistence context.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>save()</literal> does guarantee to return an
identifier. If an INSERT
- has to be executed to get the identifier ( e.g. "identity"
generator, not
- "sequence"), this INSERT happens immediately, no matter if
you are inside or
- outside of a transaction. This is problematic in a long-running
conversation
- with an extended Session/persistence context.
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>persist()</literal> makes a transient instance
+ persistent. However, it does not guarantee that the identifier value
+ will be assigned to the persistent instance immediately, the
+ assignment might happen at flush time. <literal>persist()</literal>
+ also guarantees that it will not execute an
<literal>INSERT</literal>
+ statement if it is called outside of transaction boundaries. This is
+ useful in long-running conversations with an extended
+ Session/persistence context.</para>
+ </listitem>
- <para>
- Alternatively, you can assign the identifier using an overloaded version
- of <literal>save()</literal>.
- </para>
+ <listitem>
+ <para><literal>save()</literal> does guarantee to return an
+ identifier. If an INSERT has to be executed to get the identifier (
+ e.g. "identity" generator, not "sequence"), this INSERT
happens
+ immediately, no matter if you are inside or outside of a transaction.
+ This is problematic in a long-running conversation with an extended
+ Session/persistence context.</para>
+ </listitem>
+ </itemizedlist>
-<programlisting role="JAVA"><![CDATA[DomesticCat pk = new
DomesticCat();
+ <para>Alternatively, you can assign the identifier using an overloaded
+ version of <literal>save()</literal>.</para>
+
+ <programlisting role="JAVA">DomesticCat pk = new DomesticCat();
pk.setColor(Color.TABBY);
pk.setSex('F');
pk.setName("PK");
pk.setKittens( new HashSet() );
pk.addKitten(fritz);
-sess.save( pk, new Long(1234) );]]></programlisting>
-
- <para>
- If the object you make persistent has associated objects (e.g. the
- <literal>kittens</literal> collection in the previous example),
- these objects can be made persistent in any order you like unless you
- have a <literal>NOT NULL</literal> constraint upon a foreign key
column.
- There is never a risk of violating foreign key constraints. However, you
- might violate a <literal>NOT NULL</literal> constraint if you
- <literal>save()</literal> the objects in the wrong order.
- </para>
-
- <para>
- Usually you do not bother with this detail, as you will normally use
Hibernate's
- <emphasis>transitive persistence</emphasis> feature to save the
associated
- objects automatically. Then, even <literal>NOT NULL</literal>
- constraint violations do not occur - Hibernate will take care of everything.
- Transitive persistence is discussed later in this chapter.
- </para>
-
- </section>
+sess.save( pk, new Long(1234) );</programlisting>
- <section id="objectstate-loading">
- <title>Loading an object</title>
+ <para>If the object you make persistent has associated objects (e.g. the
+ <literal>kittens</literal> collection in the previous example), these
+ objects can be made persistent in any order you like unless you have a
+ <literal>NOT NULL</literal> constraint upon a foreign key column. There
is
+ never a risk of violating foreign key constraints. However, you might
+ violate a <literal>NOT NULL</literal> constraint if you
+ <literal>save()</literal> the objects in the wrong order.</para>
- <para>
- The <literal>load()</literal> methods of
<literal>Session</literal> provide
- a way of retrieving a persistent instance if you know its identifier.
- <literal>load()</literal> takes a class object and loads the
state into
- a newly instantiated instance of that class in a persistent state.
- </para>
+ <para>Usually you do not bother with this detail, as you will normally use
+ Hibernate's <emphasis>transitive persistence</emphasis> feature to
save
+ the associated objects automatically. Then, even <literal>NOT
+ NULL</literal> constraint violations do not occur - Hibernate will take
+ care of everything. Transitive persistence is discussed later in this
+ chapter.</para>
+ </section>
- <programlisting role="JAVA"><![CDATA[Cat fritz = (Cat)
sess.load(Cat.class, generatedId);]]></programlisting>
+ <section id="objectstate-loading">
+ <title>Loading an object</title>
-<programlisting role="JAVA"><![CDATA[// you need to wrap primitive
identifiers
+ <para>The <literal>load()</literal> methods of
<literal>Session</literal>
+ provide a way of retrieving a persistent instance if you know its
+ identifier. <literal>load()</literal> takes a class object and loads the
+ state into a newly instantiated instance of that class in a persistent
+ state.</para>
+
+ <programlisting role="JAVA">Cat fritz = (Cat) sess.load(Cat.class,
generatedId);</programlisting>
+
+ <programlisting role="JAVA">// you need to wrap primitive
identifiers
long id = 1234;
-DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id)
);]]></programlisting>
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id)
);</programlisting>
- <para>
- Alternatively, you can load state into a given instance:
- </para>
+ <para>Alternatively, you can load state into a given instance:</para>
-<programlisting role="JAVA"><![CDATA[Cat cat = new DomesticCat();
+ <programlisting role="JAVA">Cat cat = new DomesticCat();
// load pk's state into cat
sess.load( cat, new Long(pkId) );
-Set kittens = cat.getKittens();]]></programlisting>
+Set kittens = cat.getKittens();</programlisting>
- <para>
- Be aware that <literal>load()</literal> will throw an
unrecoverable exception if
- there is no matching database row. If the class is mapped with a proxy,
- <literal>load()</literal> just returns an uninitialized proxy and
does not
- actually hit the database until you invoke a method of the proxy. This
- is useful if you wish to create an association to an object
- without actually loading it from the database. It also allows multiple
- instances to be loaded as a batch if
<literal>batch-size</literal> is
- defined for the class mapping.
- </para>
-
- <para>
- If you are not certain that a matching row exists, you should use the
- <literal>get()</literal> method which hits the database
immediately and
- returns null if there is no matching row.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Cat cat = (Cat)
sess.get(Cat.class, id);
+ <para>Be aware that <literal>load()</literal> will throw an
unrecoverable
+ exception if there is no matching database row. If the class is mapped
+ with a proxy, <literal>load()</literal> just returns an uninitialized
+ proxy and does not actually hit the database until you invoke a method of
+ the proxy. This is useful if you wish to create an association to an
+ object without actually loading it from the database. It also allows
+ multiple instances to be loaded as a batch if
+ <literal>batch-size</literal> is defined for the class
mapping.</para>
+
+ <para>If you are not certain that a matching row exists, you should use
+ the <literal>get()</literal> method which hits the database immediately
+ and returns null if there is no matching row.</para>
+
+ <programlisting role="JAVA">Cat cat = (Cat) sess.get(Cat.class, id);
if (cat==null) {
cat = new Cat();
sess.save(cat, id);
}
-return cat;]]></programlisting>
+return cat;</programlisting>
- <para>
- You can even load an object using an SQL <literal>SELECT ... FOR
UPDATE</literal>,
- using a <literal>LockMode</literal>. See the API documentation
for more information.
- </para>
+ <para>You can even load an object using an SQL <literal>SELECT ... FOR
+ UPDATE</literal>, using a <literal>LockMode</literal>. See the API
+ documentation for more information.</para>
- <programlisting role="JAVA"><![CDATA[Cat cat = (Cat)
sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
-
- <para>
- Any associated instances or contained collections will
- <emphasis>not</emphasis> be selected <literal>FOR
UPDATE</literal>, unless you decide
- to specify <literal>lock</literal> or
<literal>all</literal> as a
- cascade style for the association.
- </para>
-
- <para>
- It is possible to re-load an object and all its collections at any time,
using the
- <literal>refresh()</literal> method. This is useful when database
triggers are used to
- initialize some of the properties of the object.
- </para>
-
- <programlisting role="JAVA"><![CDATA[sess.save(cat);
-sess.flush(); //force the SQL INSERT
-sess.refresh(cat); //re-read the state (after the trigger
executes)]]></programlisting>
+ <programlisting role="JAVA">Cat cat = (Cat) sess.get(Cat.class, id,
LockMode.UPGRADE);</programlisting>
- <para>
- How much does Hibernate load
- from the database and how many SQL <literal>SELECT</literal>s
will it use? This
- depends on the <emphasis>fetching strategy</emphasis>. This is
explained in
- <xref linkend="performance-fetching"/>.
- </para>
+ <para>Any associated instances or contained collections will
+ <emphasis>not</emphasis> be selected <literal>FOR
UPDATE</literal>, unless
+ you decide to specify <literal>lock</literal> or
<literal>all</literal> as
+ a cascade style for the association.</para>
- </section>
+ <para>It is possible to re-load an object and all its collections at any
+ time, using the <literal>refresh()</literal> method. This is useful when
+ database triggers are used to initialize some of the properties of the
+ object.</para>
- <section id="objectstate-querying" revision="1">
- <title>Querying</title>
+ <programlisting role="JAVA">sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger
executes)</programlisting>
- <para>
- If you do not know the identifiers of the objects you are looking for,
- you need a query. Hibernate supports an easy-to-use but powerful object
- oriented query language (HQL). For programmatic query creation, Hibernate
- supports a sophisticated Criteria and Example query feature (QBC and QBE).
- You can also express your query in the native SQL of your database, with
- optional support from Hibernate for result set conversion into objects.
- </para>
+ <para>How much does Hibernate load from the database and how many SQL
+ <literal>SELECT</literal>s will it use? This depends on the
+ <emphasis>fetching strategy</emphasis>. This is explained in <xref
+ linkend="performance-fetching" />.</para>
+ </section>
- <section id="objectstate-querying-executing"
revision="1">
- <title>Executing queries</title>
+ <section id="objectstate-querying" revision="1">
+ <title>Querying</title>
- <para>
- HQL and native SQL queries are represented with an instance of
<literal>org.hibernate.Query</literal>.
- This interface offers methods for parameter binding, result set handling,
and for the execution
- of the actual query. You always obtain a
<literal>Query</literal> using the current
- <literal>Session</literal>:
- </para>
+ <para>If you do not know the identifiers of the objects you are looking
+ for, you need a query. Hibernate supports an easy-to-use but powerful
+ object oriented query language (HQL). For programmatic query creation,
+ Hibernate supports a sophisticated Criteria and Example query feature (QBC
+ and QBE). You can also express your query in the native SQL of your
+ database, with optional support from Hibernate for result set conversion
+ into objects.</para>
- <programlisting role="JAVA"><![CDATA[List cats =
session.createQuery(
- "from Cat as cat where cat.birthdate < ?")
+ <section id="objectstate-querying-executing" revision="1">
+ <title>Executing queries</title>
+
+ <para>HQL and native SQL queries are represented with an instance of
+ <literal>org.hibernate.Query</literal>. This interface offers methods
+ for parameter binding, result set handling, and for the execution of the
+ actual query. You always obtain a <literal>Query</literal> using the
+ current <literal>Session</literal>:</para>
+
+ <programlisting role="JAVA">List cats = session.createQuery(
+ "from Cat as cat where cat.birthdate < ?")
.setDate(0, date)
.list();
@@ -309,35 +273,32 @@
Query mothersWithKittens = (Cat) session.createQuery(
"select mother from Cat as mother left join fetch mother.kittens");
-Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+Set uniqueMothers = new HashSet(mothersWithKittens.list());</programlisting>
- <para>
- A query is usually executed by invoking
<literal>list()</literal>. The
- result of the query will be loaded completely into a collection in
memory.
- Entity instances retrieved by a query are in a persistent state. The
- <literal>uniqueResult()</literal> method offers a shortcut if
you
- know your query will only return a single object. Queries that
- make use of eager fetching of collections usually return duplicates of
- the root objects, but with their collections initialized. You can filter
- these duplicates through a <literal>Set</literal>.
- </para>
+ <para>A query is usually executed by invoking
<literal>list()</literal>.
+ The result of the query will be loaded completely into a collection in
+ memory. Entity instances retrieved by a query are in a persistent state.
+ The <literal>uniqueResult()</literal> method offers a shortcut if you
+ know your query will only return a single object. Queries that make use
+ of eager fetching of collections usually return duplicates of the root
+ objects, but with their collections initialized. You can filter these
+ duplicates through a <literal>Set</literal>.</para>
- <section id="objectstate-querying-executing-iterate">
- <title>Iterating results</title>
+ <section id="objectstate-querying-executing-iterate">
+ <title>Iterating results</title>
- <para>
- Occasionally, you might be able to achieve better performance by
- executing the query using the
<literal>iterate()</literal> method.
- This will usually be the case if you expect that the actual
- entity instances returned by the query will already be in the
session
- or second-level cache. If they are not already cached,
- <literal>iterate()</literal> will be slower than
<literal>list()</literal>
- and might require many database hits for a simple query, usually
- <emphasis>1</emphasis> for the initial select which only
returns identifiers,
- and <emphasis>n</emphasis> additional selects to
initialize the actual instances.
- </para>
+ <para>Occasionally, you might be able to achieve better performance by
+ executing the query using the <literal>iterate()</literal> method.
+ This will usually be the case if you expect that the actual entity
+ instances returned by the query will already be in the session or
+ second-level cache. If they are not already cached,
+ <literal>iterate()</literal> will be slower than
+ <literal>list()</literal> and might require many database hits for a
+ simple query, usually <emphasis>1</emphasis> for the initial select
+ which only returns identifiers, and <emphasis>n</emphasis>
additional
+ selects to initialize the actual instances.</para>
- <programlisting role="JAVA"><![CDATA[// fetch ids
+ <programlisting role="JAVA">// fetch ids
Iterator iter = sess.createQuery("from eg.Qux q order by
q.likeliness").iterate();
while ( iter.hasNext() ) {
Qux qux = (Qux) iter.next(); // fetch the object
@@ -348,18 +309,16 @@
// dont need to process the rest
break;
}
-}]]></programlisting>
- </section>
-
- <section id="objectstate-querying-executing-tuples">
- <title>Queries that return tuples</title>
+}</programlisting>
+ </section>
- <para>
- Hibernate queries sometimes return tuples of objects. Each tuple
- is returned as an array:
- </para>
+ <section id="objectstate-querying-executing-tuples">
+ <title>Queries that return tuples</title>
- <programlisting role="JAVA"><![CDATA[Iterator
kittensAndMothers = sess.createQuery(
+ <para>Hibernate queries sometimes return tuples of objects. Each tuple
+ is returned as an array:</para>
+
+ <programlisting role="JAVA">Iterator kittensAndMothers =
sess.createQuery(
"select kitten, mother from Cat kitten join kitten.mother mother")
.list()
.iterator();
@@ -369,20 +328,18 @@
Cat kitten = (Cat) tuple[0];
Cat mother = (Cat) tuple[1];
....
-}]]></programlisting>
+}</programlisting>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-scalar"
revision="1">
+ <title>Scalar results</title>
- <section id="objectstate-querying-executing-scalar"
revision="1">
- <title>Scalar results</title>
+ <para>Queries can specify a property of a class in the
+ <literal>select</literal> clause. They can even call SQL aggregate
+ functions. Properties or aggregates are considered "scalar" results
+ and not entities in persistent state.</para>
- <para>
- Queries can specify a property of a class in the
<literal>select</literal> clause.
- They can even call SQL aggregate functions. Properties or aggregates
are considered
- "scalar" results and not entities in persistent state.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Iterator results
= sess.createQuery(
+ <programlisting role="JAVA">Iterator results = sess.createQuery(
"select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
"group by cat.color")
.list()
@@ -394,92 +351,79 @@
Date oldest = (Date) row[1];
Integer count = (Integer) row[2];
.....
-}]]></programlisting>
+}</programlisting>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-parameters">
+ <title>Bind parameters</title>
- <section id="objectstate-querying-executing-parameters">
- <title>Bind parameters</title>
+ <para>Methods on <literal>Query</literal> are provided for
binding
+ values to named parameters or JDBC-style <literal>?</literal>
+ parameters. <emphasis>Contrary to JDBC, Hibernate numbers parameters
+ from zero.</emphasis> Named parameters are identifiers of the form
+ <literal>:name</literal> in the query string. The advantages of
named
+ parameters are as follows:</para>
- <para>
- Methods on <literal>Query</literal> are provided for
binding values to
- named parameters or JDBC-style <literal>?</literal>
parameters.
- <emphasis>Contrary to JDBC, Hibernate numbers parameters from
zero.</emphasis>
- Named parameters are identifiers of the form
<literal>:name</literal> in
- the query string. The advantages of named parameters are as follows:
- </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>named parameters are insensitive to the order they occur in
+ the query string</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- named parameters are insensitive to the order they occur in
the
- query string
- </para>
- </listitem>
- <listitem>
- <para>
- they can occur multiple times in the same query
- </para>
- </listitem>
- <listitem>
- <para>
- they are self-documenting
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>they can occur multiple times in the same query</para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[//named parameter
(preferred)
+ <listitem>
+ <para>they are self-documenting</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting role="JAVA">//named parameter (preferred)
Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
q.setString("name", "Fritz");
-Iterator cats = q.iterate();]]></programlisting>
+Iterator cats = q.iterate();</programlisting>
- <programlisting role="JAVA"><![CDATA[//positional
parameter
+ <programlisting role="JAVA">//positional parameter
Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
q.setString(0, "Izi");
-Iterator cats = q.iterate();]]></programlisting>
+Iterator cats = q.iterate();</programlisting>
- <programlisting role="JAVA"><![CDATA[//named parameter
list
+ <programlisting role="JAVA">//named parameter list
List names = new ArrayList();
names.add("Izi");
names.add("Fritz");
Query q = sess.createQuery("from DomesticCat cat where cat.name in
(:namesList)");
q.setParameterList("namesList", names);
-List cats = q.list();]]></programlisting>
+List cats = q.list();</programlisting>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-pagination">
+ <title>Pagination</title>
- <section id="objectstate-querying-executing-pagination">
- <title>Pagination</title>
+ <para>If you need to specify bounds upon your result set, that is, the
+ maximum number of rows you want to retrieve and/or the first row you
+ want to retrieve, you can use methods of the
<literal>Query</literal>
+ interface:</para>
- <para>
- If you need to specify bounds upon your result set, that is, the
maximum number of rows
- you want to retrieve and/or the first row you want to retrieve, you
can
- use methods of the <literal>Query</literal> interface:
- </para>
-
- <programlisting role="JAVA"><![CDATA[Query q =
sess.createQuery("from DomesticCat cat");
+ <programlisting role="JAVA">Query q = sess.createQuery("from
DomesticCat cat");
q.setFirstResult(20);
q.setMaxResults(10);
-List cats = q.list();]]></programlisting>
+List cats = q.list();</programlisting>
- <para>
- Hibernate knows how to translate this limit query into the native
- SQL of your DBMS.
- </para>
+ <para>Hibernate knows how to translate this limit query into the
+ native SQL of your DBMS.</para>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-scrolling">
+ <title>Scrollable iteration</title>
- <section id="objectstate-querying-executing-scrolling">
- <title>Scrollable iteration</title>
+ <para>If your JDBC driver supports scrollable
+ <literal>ResultSet</literal>s, the
<literal>Query</literal> interface
+ can be used to obtain a <literal>ScrollableResults</literal> object
+ that allows flexible navigation of the query results.</para>
- <para>
- If your JDBC driver supports scrollable
<literal>ResultSet</literal>s, the
- <literal>Query</literal> interface can be used to obtain
a
- <literal>ScrollableResults</literal> object that allows
flexible
- navigation of the query results.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Query q =
sess.createQuery("select cat.name, cat from DomesticCat cat " +
+ <programlisting role="JAVA">Query q =
sess.createQuery("select cat.name, cat from DomesticCat cat " +
"order by cat.name");
ScrollableResults cats = q.scroll();
if ( cats.first() ) {
@@ -496,215 +440,188 @@
pageOfCats = new ArrayList();
cats.beforeFirst();
int i=0;
- while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1)
);
+ while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add(
cats.get(1) );
}
-cats.close()]]></programlisting>
+cats.close()</programlisting>
- <para>
- Note that an open database connection and cursor is required for
this
- functionality. Use
<literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
- if you need offline pagination functionality.
- </para>
+ <para>Note that an open database connection and cursor is required for
+ this functionality. Use
+
<literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+ if you need offline pagination functionality.</para>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-named"
revision="1">
+ <title>Externalizing named queries</title>
- <section id="objectstate-querying-executing-named"
revision="1">
- <title>Externalizing named queries</title>
+ <para>You can also define named queries in the mapping document.
+ Remember to use a <literal>CDATA</literal> section if your query
+ contains characters that could be interpreted as markup.</para>
- <para>
- You can also define named queries in the mapping document. Remember
to use a
- <literal>CDATA</literal> section if your query contains
characters that could
- be interpreted as markup.
- </para>
-
- <programlisting role="XML"><![CDATA[<query
name="ByNameAndMaximumWeight"><![CDATA[
+ <programlisting role="XML"><query
name="ByNameAndMaximumWeight"><![CDATA[
from eg.DomesticCat as cat
where cat.name = ?
- and cat.weight > ?
-] ]></query>]]></programlisting>
+ and cat.weight > ?
+] ]></query></programlisting>
- <para>
- Parameter binding and executing is done programatically:
- </para>
+ <para>Parameter binding and executing is done
programatically:</para>
- <programlisting role="JAVA"><![CDATA[Query q =
sess.getNamedQuery("ByNameAndMaximumWeight");
+ <programlisting role="JAVA">Query q =
sess.getNamedQuery("ByNameAndMaximumWeight");
q.setString(0, name);
q.setInt(1, minWeight);
-List cats = q.list();]]></programlisting>
+List cats = q.list();</programlisting>
- <para>
- The actual program code is independent of the query language that
- is used. You can also define native SQL queries in metadata, or
migrate
- existing queries to Hibernate by placing them in mapping files.
- </para>
+ <para>The actual program code is independent of the query language
+ that is used. You can also define native SQL queries in metadata, or
+ migrate existing queries to Hibernate by placing them in mapping
+ files.</para>
- <para>
- Also note that a query declaration inside a
<literal><hibernate-mapping></literal>
- element requires a global unique name for the query, while a query
declaration inside a
- <literal><class></literal> element is made
unique automatically by prepending the
- fully qualified name of the class. For example
- <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
- </para>
+ <para>Also note that a query declaration inside a
+ <literal><hibernate-mapping></literal> element requires
a global
+ unique name for the query, while a query declaration inside a
+ <literal><class></literal> element is made unique
automatically
+ by prepending the fully qualified name of the class. For example
+ <literal>eg.Cat.ByNameAndMaximumWeight</literal>.</para>
+ </section>
+ </section>
- </section>
+ <section id="objectstate-filtering" revision="1">
+ <title>Filtering collections</title>
- </section>
+ <para>A collection <emphasis>filter</emphasis> is a special type
of
+ query that can be applied to a persistent collection or array. The query
+ string can refer to <literal>this</literal>, meaning the current
+ collection element.</para>
- <section id="objectstate-filtering" revision="1">
- <title>Filtering collections</title>
- <para>
- A collection <emphasis>filter</emphasis> is a special type of
query that can be applied to
- a persistent collection or array. The query string can refer to
<literal>this</literal>,
- meaning the current collection element.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Collection
blackKittens = session.createFilter(
+ <programlisting role="JAVA">Collection blackKittens =
session.createFilter(
pk.getKittens(),
"where this.color = ?")
.setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
.list()
-);]]></programlisting>
-
- <para>
- The returned collection is considered a bag that is a copy of the given
- collection. The original collection is not modified. This is contrary to
- the implication of the name "filter", but consistent with
expected behavior.
- </para>
+);</programlisting>
- <para>
- Observe that filters do not require a <literal>from</literal>
clause, although they can have
- one if required. Filters are not limited to returning the collection
elements themselves.
- </para>
+ <para>The returned collection is considered a bag that is a copy of the
+ given collection. The original collection is not modified. This is
+ contrary to the implication of the name "filter", but consistent with
+ expected behavior.</para>
- <programlisting role="JAVA"><![CDATA[Collection
blackKittenMates = session.createFilter(
+ <para>Observe that filters do not require a
<literal>from</literal>
+ clause, although they can have one if required. Filters are not limited
+ to returning the collection elements themselves.</para>
+
+ <programlisting role="JAVA">Collection blackKittenMates =
session.createFilter(
pk.getKittens(),
"select this.mate where this.color = eg.Color.BLACK.intValue")
- .list();]]></programlisting>
+ .list();</programlisting>
- <para>
- Even an empty filter query is useful, e.g. to load a subset of elements
in a
- large collection:
- </para>
+ <para>Even an empty filter query is useful, e.g. to load a subset of
+ elements in a large collection:</para>
- <programlisting role="JAVA"><![CDATA[Collection tenKittens
= session.createFilter(
+ <programlisting role="JAVA">Collection tenKittens =
session.createFilter(
mother.getKittens(), "")
.setFirstResult(0).setMaxResults(10)
- .list();]]></programlisting>
+ .list();</programlisting>
+ </section>
- </section>
+ <section id="objecstate-querying-criteria" revision="1">
+ <title>Criteria queries</title>
- <section id="objecstate-querying-criteria"
revision="1">
- <title>Criteria queries</title>
+ <para>HQL is extremely powerful, but some developers prefer to build
+ queries dynamically using an object-oriented API, rather than building
+ query strings. Hibernate provides an intuitive
+ <literal>Criteria</literal> query API for these cases:</para>
- <para>
- HQL is extremely powerful, but some developers prefer to build queries
dynamically
- using an object-oriented API, rather than building query strings.
Hibernate provides
- an intuitive <literal>Criteria</literal> query API for these
cases:
- </para>
-
- <programlisting role="JAVA"><![CDATA[Criteria crit =
session.createCriteria(Cat.class);
+ <programlisting role="JAVA">Criteria crit =
session.createCriteria(Cat.class);
crit.add( Restrictions.eq( "color", eg.Color.BLACK ) );
crit.setMaxResults(10);
-List cats = crit.list();]]></programlisting>
-
- <para>
- The <literal>Criteria</literal> and the associated
<literal>Example</literal>
- API are discussed in more detail in <xref
linkend="querycriteria"/>.
- </para>
+List cats = crit.list();</programlisting>
- </section>
+ <para>The <literal>Criteria</literal> and the associated
+ <literal>Example</literal> API are discussed in more detail in
<xref
+ linkend="querycriteria" />.</para>
+ </section>
- <section id="objectstate-querying-nativesql"
revision="2">
- <title>Queries in native SQL</title>
+ <section id="objectstate-querying-nativesql" revision="2">
+ <title>Queries in native SQL</title>
- <para>
- You can express a query in SQL, using
<literal>createSQLQuery()</literal> and
- let Hibernate manage the mapping from result sets to objects.
- You can at any time call
<literal>session.connection()</literal> and
- use the JDBC <literal>Connection</literal> directly. If you
choose to use the
- Hibernate API, you must enclose SQL aliases in braces:
- </para>
+ <para>You can express a query in SQL, using
+ <literal>createSQLQuery()</literal> and let Hibernate manage the
mapping
+ from result sets to objects. You can at any time call
+ <literal>session.connection()</literal> and use the JDBC
+ <literal>Connection</literal> directly. If you choose to use the
+ Hibernate API, you must enclose SQL aliases in braces:</para>
- <programlisting role="JAVA"><![CDATA[List cats =
session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
+ <programlisting role="JAVA">List cats =
session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
-.list();]]></programlisting>
-
- <programlisting role="JAVA"><![CDATA[List cats =
session.createSQLQuery(
+.list();</programlisting>
+
+ <programlisting role="JAVA">List cats = session.createSQLQuery(
"SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
"{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
- "FROM CAT {cat} WHERE ROWNUM<10")
+ "FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
-.list()]]></programlisting>
+.list()</programlisting>
- <para>
- SQL queries can contain named and positional parameters, just like
Hibernate queries.
- More information about native SQL queries in Hibernate can be found in
- <xref linkend="querysql"/>.
- </para>
-
- </section>
-
+ <para>SQL queries can contain named and positional parameters, just like
+ Hibernate queries. More information about native SQL queries in
+ Hibernate can be found in <xref linkend="querysql"
/>.</para>
</section>
+ </section>
- <section id="objectstate-modifying" revision="1">
- <title>Modifying persistent objects</title>
+ <section id="objectstate-modifying" revision="1">
+ <title>Modifying persistent objects</title>
- <para>
- <emphasis>Transactional persistent instances</emphasis> (i.e.
objects loaded, saved, created or
- queried by the <literal>Session</literal>) can be manipulated by
the application,
- and any changes to persistent state will be persisted when the
<literal>Session</literal>
- is <emphasis>flushed</emphasis>. This is discussed later in this
chapter. There is no need
- to call a particular method (like <literal>update()</literal>,
which has a different
- purpose) to make your modifications persistent. The most straightforward way
to update
- the state of an object is to <literal>load()</literal> it
- and then manipulate it directly while the
<literal>Session</literal> is open:
- </para>
+ <para><emphasis>Transactional persistent instances</emphasis>
(i.e.
+ objects loaded, saved, created or queried by the
+ <literal>Session</literal>) can be manipulated by the application, and
any
+ changes to persistent state will be persisted when the
+ <literal>Session</literal> is <emphasis>flushed</emphasis>.
This is
+ discussed later in this chapter. There is no need to call a particular
+ method (like <literal>update()</literal>, which has a different purpose)
+ to make your modifications persistent. The most straightforward way to
+ update the state of an object is to <literal>load()</literal> it and
then
+ manipulate it directly while the <literal>Session</literal> is
+ open:</para>
- <programlisting role="JAVA"><![CDATA[DomesticCat cat =
(DomesticCat) sess.load( Cat.class, new Long(69) );
+ <programlisting role="JAVA">DomesticCat cat = (DomesticCat)
sess.load( Cat.class, new Long(69) );
cat.setName("PK");
-sess.flush(); // changes to cat are automatically detected and
persisted]]></programlisting>
+sess.flush(); // changes to cat are automatically detected and
persisted</programlisting>
- <para>
- Sometimes this programming model is inefficient, as it requires in the same
session both an SQL
- <literal>SELECT</literal> to load an object and an SQL
<literal>UPDATE</literal>
- to persist its updated state. Hibernate offers an
- alternate approach by using detached instances.
- </para>
+ <para>Sometimes this programming model is inefficient, as it requires in
+ the same session both an SQL <literal>SELECT</literal> to load an object
+ and an SQL <literal>UPDATE</literal> to persist its updated state.
+ Hibernate offers an alternate approach by using detached instances.</para>
- <important><para>
- Hibernate does not offer its own API for direct execution of
- <literal>UPDATE</literal> or
<literal>DELETE</literal> statements. Hibernate is a
- <emphasis>state management</emphasis> service, you do not have to
think in
- <emphasis>statements</emphasis> to use it. JDBC is a perfect API
for executing
- SQL statements, you can get a JDBC <literal>Connection</literal>
at any time
- by calling <literal>session.connection()</literal>. Furthermore,
the notion
- of mass operations conflicts with object/relational mapping for online
- transaction processing-oriented applications. Future versions of Hibernate
- can, however, provide special mass operation functions. See <xref
linkend="batch"/>
- for some possible batch operation tricks.
- </para>
-</important>
+ <important>
+ <para>Hibernate does not offer its own API for direct execution of
+ <literal>UPDATE</literal> or <literal>DELETE</literal>
statements.
+ Hibernate is a <emphasis>state management</emphasis> service, you do
not
+ have to think in <emphasis>statements</emphasis> to use it. JDBC is a
+ perfect API for executing SQL statements, you can get a JDBC
+ <literal>Connection</literal> at any time by calling
+ <literal>session.connection()</literal>. Furthermore, the notion of
mass
+ operations conflicts with object/relational mapping for online
+ transaction processing-oriented applications. Future versions of
+ Hibernate can, however, provide special mass operation functions. See
+ <xref linkend="batch" /> for some possible batch operation
+ tricks.</para>
+ </important>
+ </section>
- </section>
+ <section id="objectstate-detached" revision="2">
+ <title>Modifying detached objects</title>
- <section id="objectstate-detached" revision="2">
- <title>Modifying detached objects</title>
+ <para>Many applications need to retrieve an object in one transaction,
+ send it to the UI layer for manipulation, then save the changes in a new
+ transaction. Applications that use this kind of approach in a
+ high-concurrency environment usually use versioned data to ensure
+ isolation for the "long" unit of work.</para>
- <para>
- Many applications need to retrieve an object in one transaction, send it to
the
- UI layer for manipulation, then save the changes in a new transaction.
- Applications that use this kind of approach in a high-concurrency
environment
- usually use versioned data to ensure isolation for the "long" unit
of work.
- </para>
+ <para>Hibernate supports this model by providing for reattachment of
+ detached instances using the <literal>Session.update()</literal> or
+ <literal>Session.merge()</literal> methods:</para>
- <para>
- Hibernate supports this model by providing for reattachment of detached
instances
- using the <literal>Session.update()</literal> or
<literal>Session.merge()</literal>
- methods:
- </para>
-
- <programlisting role="JAVA"><![CDATA[// in the first session
+ <programlisting role="JAVA">// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catId);
Cat potentialMate = new Cat();
firstSession.save(potentialMate);
@@ -714,66 +631,57 @@
// later, in a new session
secondSession.update(cat); // update cat
-secondSession.update(mate); // update mate]]></programlisting>
+secondSession.update(mate); // update mate</programlisting>
- <para>
- If the <literal>Cat</literal> with identifier
<literal>catId</literal> had already
- been loaded by <literal>secondSession</literal> when the
application tried to
- reattach it, an exception would have been thrown.
- </para>
+ <para>If the <literal>Cat</literal> with identifier
+ <literal>catId</literal> had already been loaded by
+ <literal>secondSession</literal> when the application tried to reattach
+ it, an exception would have been thrown.</para>
- <para>
- Use <literal>update()</literal> if you are certain that the
session does
- not contain an already persistent instance with the same identifier. Use
- <literal>merge()</literal> if you want to merge your
modifications at any time
- without consideration of the state of the session. In other words,
<literal>update()</literal>
- is usually the first method you would call in a fresh session, ensuring that
- the reattachment of your detached instances is the first operation that is
executed.
- </para>
+ <para>Use <literal>update()</literal> if you are certain that the
session
+ does not contain an already persistent instance with the same identifier.
+ Use <literal>merge()</literal> if you want to merge your modifications
at
+ any time without consideration of the state of the session. In other
+ words, <literal>update()</literal> is usually the first method you would
+ call in a fresh session, ensuring that the reattachment of your detached
+ instances is the first operation that is executed.</para>
- <para>
- The application should individually <literal>update()</literal>
detached instances
- that are reachable from the given detached instance
<emphasis>only</emphasis> if it wants
- their state to be updated. This can be automated using
<emphasis>transitive
- persistence</emphasis>. See <xref
linkend="objectstate-transitive"/> for more information.
- </para>
+ <para>The application should individually
<literal>update()</literal>
+ detached instances that are reachable from the given detached instance
+ <emphasis>only</emphasis> if it wants their state to be updated. This
can
+ be automated using <emphasis>transitive persistence</emphasis>. See
<xref
+ linkend="objectstate-transitive" /> for more information.</para>
- <para>
- The <literal>lock()</literal> method also allows an application
to reassociate
- an object with a new session. However, the detached instance has to be
unmodified.
- </para>
+ <para>The <literal>lock()</literal> method also allows an
application to
+ reassociate an object with a new session. However, the detached instance
+ has to be unmodified.</para>
- <programlisting role="JAVA"><![CDATA[//just reassociate:
+ <programlisting role="JAVA">//just reassociate:
sess.lock(fritz, LockMode.NONE);
//do a version check, then reassociate:
sess.lock(izi, LockMode.READ);
//do a version check, using SELECT ... FOR UPDATE, then reassociate:
-sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+sess.lock(pk, LockMode.UPGRADE);</programlisting>
- <para>
- Note that <literal>lock()</literal> can be used with various
- <literal>LockMode</literal>s. See the API documentation and the
- chapter on transaction handling for more information. Reattachment is not
- the only usecase for <literal>lock()</literal>.
- </para>
+ <para>Note that <literal>lock()</literal> can be used with various
+ <literal>LockMode</literal>s. See the API documentation and the chapter
on
+ transaction handling for more information. Reattachment is not the only
+ usecase for <literal>lock()</literal>.</para>
- <para>
- Other models for long units of work are discussed in <xref
linkend="transactions-optimistic"/>.
- </para>
+ <para>Other models for long units of work are discussed in <xref
+ linkend="transactions-optimistic" />.</para>
+ </section>
- </section>
+ <section id="objectstate-saveorupdate">
+ <title>Automatic state detection</title>
- <section id="objectstate-saveorupdate">
- <title>Automatic state detection</title>
+ <para>Hibernate users have requested a general purpose method that either
+ saves a transient instance by generating a new identifier or
+ updates/reattaches the detached instances associated with its current
+ identifier. The <literal>saveOrUpdate()</literal> method implements this
+ functionality.</para>
- <para>
- Hibernate users have requested a general purpose method that either saves a
- transient instance by generating a new identifier or updates/reattaches
- the detached instances associated with its current identifier.
- The <literal>saveOrUpdate()</literal> method implements this
functionality.
- </para>
-
- <programlisting role="JAVA"><![CDATA[// in the first session
+ <programlisting role="JAVA">// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catID);
// in a higher tier of the application
@@ -782,157 +690,129 @@
// later, in a new session
secondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id)
-secondSession.saveOrUpdate(mate); // save the new instance (mate has a null
id)]]></programlisting>
+secondSession.saveOrUpdate(mate); // save the new instance (mate has a null
id)</programlisting>
- <para>
- The usage and semantics of <literal>saveOrUpdate()</literal>
seems to be confusing
- for new users. Firstly, so long as you are not trying to use instances from
one session
- in another new session, you should not need to use
<literal>update()</literal>,
- <literal>saveOrUpdate()</literal>, or
<literal>merge()</literal>. Some whole
- applications will never use either of these methods.
- </para>
+ <para>The usage and semantics of <literal>saveOrUpdate()</literal>
seems
+ to be confusing for new users. Firstly, so long as you are not trying to
+ use instances from one session in another new session, you should not need
+ to use <literal>update()</literal>,
<literal>saveOrUpdate()</literal>, or
+ <literal>merge()</literal>. Some whole applications will never use
either
+ of these methods.</para>
- <para>
- Usually <literal>update()</literal> or
<literal>saveOrUpdate()</literal> are used in
- the following scenario:
- </para>
+ <para>Usually <literal>update()</literal> or
+ <literal>saveOrUpdate()</literal> are used in the following
+ scenario:</para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- the application loads an object in the first session
- </para>
- </listitem>
- <listitem>
- <para>
- the object is passed up to the UI tier
- </para>
- </listitem>
- <listitem>
- <para>
- some modifications are made to the object
- </para>
- </listitem>
- <listitem>
- <para>
- the object is passed back down to the business logic tier
- </para>
- </listitem>
- <listitem>
- <para>
- the application persists these modifications by calling
- <literal>update()</literal> in a second session
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>the application loads an object in the first session</para>
+ </listitem>
- <para>
- <literal>saveOrUpdate()</literal> does the following:
- </para>
+ <listitem>
+ <para>the object is passed up to the UI tier</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- if the object is already persistent in this session, do nothing
- </para>
- </listitem>
- <listitem>
- <para>
- if another object associated with the session has the same
identifier,
- throw an exception
- </para>
- </listitem>
- <listitem>
- <para>
- if the object has no identifier property,
<literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- if the object's identifier has the value assigned to a newly
instantiated
- object, <literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- if the object is versioned by a
<literal><version></literal> or
- <literal><timestamp></literal>, and the
version property value
- is the same value assigned to a newly instantiated object,
- <literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- otherwise <literal>update()</literal> the object
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>some modifications are made to the object</para>
+ </listitem>
- <para>
- and <literal>merge()</literal> is very different:
- </para>
+ <listitem>
+ <para>the object is passed back down to the business logic
tier</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- if there is a persistent instance with the same identifier currently
- associated with the session, copy the state of the given object onto
- the persistent instance
- </para>
- </listitem>
- <listitem>
- <para>
- if there is no persistent instance currently associated with the
session,
- try to load it from the database, or create a new persistent
instance
- </para>
- </listitem>
- <listitem>
- <para>
- the persistent instance is returned
- </para>
- </listitem>
- <listitem>
- <para>
- the given instance does not become associated with the session, it
- remains detached
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>the application persists these modifications by calling
+ <literal>update()</literal> in a second session</para>
+ </listitem>
+ </itemizedlist>
- </section>
+ <para><literal>saveOrUpdate()</literal> does the
following:</para>
- <section id="objectstate-deleting" revision="1">
- <title>Deleting persistent objects</title>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>if the object is already persistent in this session, do
+ nothing</para>
+ </listitem>
- <para>
- <literal>Session.delete()</literal> will remove an object's
state from the database.
- Your application, however, can still hold a reference to a deleted object.
- It is best to think of <literal>delete()</literal> as making a
persistent instance,
- transient.
- </para>
+ <listitem>
+ <para>if another object associated with the session has the same
+ identifier, throw an exception</para>
+ </listitem>
- <programlisting
role="JAVA"><![CDATA[sess.delete(cat);]]></programlisting>
+ <listitem>
+ <para>if the object has no identifier property,
+ <literal>save()</literal> it</para>
+ </listitem>
- <para>
- You can delete objects in any order, without risk of foreign key
- constraint violations. It is still possible to violate a <literal>NOT
- NULL</literal> constraint on a foreign key column by deleting objects
in
- the wrong order, e.g. if you delete the parent, but forget to delete the
- children.
- </para>
+ <listitem>
+ <para>if the object's identifier has the value assigned to a newly
+ instantiated object, <literal>save()</literal> it</para>
+ </listitem>
- </section>
-
- <section id="objectstate-replicating" revision="1">
- <title>Replicating object between two different datastores</title>
-
- <para>
- It is sometimes useful to be able to take a graph of persistent instances
- and make them persistent in a different datastore, without regenerating
identifier
- values.
- </para>
-
- <programlisting role="JAVA"><![CDATA[//retrieve a cat from one
database
+ <listitem>
+ <para>if the object is versioned by a
+ <literal><version></literal> or
+ <literal><timestamp></literal>, and the version
property value
+ is the same value assigned to a newly instantiated object,
+ <literal>save()</literal> it</para>
+ </listitem>
+
+ <listitem>
+ <para>otherwise <literal>update()</literal> the
object</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>and <literal>merge()</literal> is very
different:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>if there is a persistent instance with the same identifier
+ currently associated with the session, copy the state of the given
+ object onto the persistent instance</para>
+ </listitem>
+
+ <listitem>
+ <para>if there is no persistent instance currently associated with the
+ session, try to load it from the database, or create a new persistent
+ instance</para>
+ </listitem>
+
+ <listitem>
+ <para>the persistent instance is returned</para>
+ </listitem>
+
+ <listitem>
+ <para>the given instance does not become associated with the session,
+ it remains detached</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section id="objectstate-deleting" revision="1">
+ <title>Deleting persistent objects</title>
+
+ <para><literal>Session.delete()</literal> will remove an
object's state
+ from the database. Your application, however, can still hold a reference
+ to a deleted object. It is best to think of <literal>delete()</literal>
as
+ making a persistent instance, transient.</para>
+
+ <programlisting role="JAVA">sess.delete(cat);</programlisting>
+
+ <para>You can delete objects in any order, without risk of foreign key
+ constraint violations. It is still possible to violate a <literal>NOT
+ NULL</literal> constraint on a foreign key column by deleting objects in
+ the wrong order, e.g. if you delete the parent, but forget to delete the
+ children.</para>
+ </section>
+
+ <section id="objectstate-replicating" revision="1">
+ <title>Replicating object between two different datastores</title>
+
+ <para>It is sometimes useful to be able to take a graph of persistent
+ instances and make them persistent in a different datastore, without
+ regenerating identifier values.</para>
+
+ <programlisting role="JAVA">//retrieve a cat from one database
Session session1 = factory1.openSession();
Transaction tx1 = session1.beginTransaction();
Cat cat = session1.get(Cat.class, catId);
@@ -944,140 +824,117 @@
Transaction tx2 = session2.beginTransaction();
session2.replicate(cat, ReplicationMode.LATEST_VERSION);
tx2.commit();
-session2.close();]]></programlisting>
+session2.close();</programlisting>
- <para>
- The <literal>ReplicationMode</literal> determines how
<literal>replicate()</literal>
- will deal with conflicts with existing rows in the database:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>ReplicationMode.IGNORE</literal>: ignores the
object when there is
- an existing database row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.OVERWRITE</literal>: overwrites
any existing database
- row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.EXCEPTION</literal>: throws an
exception if there is
- an existing database row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.LATEST_VERSION</literal>:
overwrites the row if its
- version number is earlier than the version number of the object, or
ignore
- the object otherwise
- </para>
- </listitem>
- </itemizedlist>
+ <para>The <literal>ReplicationMode</literal> determines how
+ <literal>replicate()</literal> will deal with conflicts with existing
rows
+ in the database:</para>
- <para>
- Usecases for this feature include reconciling data entered into different
database
- instances, upgrading system configuration information during product
upgrades,
- rolling back changes made during non-ACID transactions and more.
- </para>
-
- </section>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>ReplicationMode.IGNORE</literal>: ignores the
object
+ when there is an existing database row with the same identifier</para>
+ </listitem>
- <section id="objectstate-flushing">
- <title>Flushing the Session</title>
+ <listitem>
+ <para><literal>ReplicationMode.OVERWRITE</literal>: overwrites
any
+ existing database row with the same identifier</para>
+ </listitem>
- <para>
- Sometimes the <literal>Session</literal> will execute the SQL
statements
- needed to synchronize the JDBC connection's state with the state of
objects held in
- memory. This process, called <emphasis>flush</emphasis>, occurs
by default at the following
- points:
- </para>
+ <listitem>
+ <para><literal>ReplicationMode.EXCEPTION</literal>: throws an
+ exception if there is an existing database row with the same
+ identifier</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- before some query executions
- </para>
- </listitem>
- <listitem>
- <para>
- from
<literal>org.hibernate.Transaction.commit()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- from <literal>Session.flush()</literal>
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para><literal>ReplicationMode.LATEST_VERSION</literal>:
overwrites
+ the row if its version number is earlier than the version number of
+ the object, or ignore the object otherwise</para>
+ </listitem>
+ </itemizedlist>
- <para>
- The SQL statements are issued in the following order:
- </para>
+ <para>Usecases for this feature include reconciling data entered into
+ different database instances, upgrading system configuration information
+ during product upgrades, rolling back changes made during non-ACID
+ transactions and more.</para>
+ </section>
- <orderedlist spacing="compact">
- <listitem>
- <para>
- all entity insertions in the same order the corresponding objects
- were saved using <literal>Session.save()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- all entity updates
- </para>
- </listitem>
- <listitem>
- <para>
- all collection deletions
- </para>
- </listitem>
- <listitem>
- <para>
- all collection element deletions, updates and insertions
- </para>
- </listitem>
- <listitem>
- <para>
- all collection insertions
- </para>
- </listitem>
- <listitem>
- <para>
- all entity deletions in the same order the corresponding objects
- were deleted using <literal>Session.delete()</literal>
- </para>
- </listitem>
- </orderedlist>
+ <section id="objectstate-flushing">
+ <title>Flushing the Session</title>
- <para>
- An exception is that objects using <literal>native</literal> ID
generation are
- inserted when they are saved.
- </para>
+ <para>Sometimes the <literal>Session</literal> will execute the
SQL
+ statements needed to synchronize the JDBC connection's state with the
+ state of objects held in memory. This process, called
+ <emphasis>flush</emphasis>, occurs by default at the following
+ points:</para>
- <para>
- Except when you explicitly <literal>flush()</literal>, there are
absolutely no
- guarantees about <emphasis>when</emphasis> the
<literal>Session</literal> executes
- the JDBC calls, only the <emphasis>order</emphasis> in which they
are executed.
- However, Hibernate does guarantee that the
<literal>Query.list(..)</literal>
- will never return stale or incorrect data.
- </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>before some query executions</para>
+ </listitem>
- <para>
- It is possible to change the default behavior so that flush occurs less
frequently.
- The <literal>FlushMode</literal> class defines three different
modes: only flush
- at commit time when the Hibernate <literal>Transaction</literal>
API
- is used, flush automatically using the explained routine, or never flush
unless
- <literal>flush()</literal> is called explicitly. The last mode is
useful for long running
- units of work, where a <literal>Session</literal> is kept open
and disconnected for
- a long time (see <xref
linkend="transactions-optimistic-longsession"/>).
- </para>
+ <listitem>
+ <para>from
+ <literal>org.hibernate.Transaction.commit()</literal></para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[sess = sf.openSession();
+ <listitem>
+ <para>from <literal>Session.flush()</literal></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The SQL statements are issued in the following order:</para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>all entity insertions in the same order the corresponding
+ objects were saved using
<literal>Session.save()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>all entity updates</para>
+ </listitem>
+
+ <listitem>
+ <para>all collection deletions</para>
+ </listitem>
+
+ <listitem>
+ <para>all collection element deletions, updates and
insertions</para>
+ </listitem>
+
+ <listitem>
+ <para>all collection insertions</para>
+ </listitem>
+
+ <listitem>
+ <para>all entity deletions in the same order the corresponding objects
+ were deleted using <literal>Session.delete()</literal></para>
+ </listitem>
+ </orderedlist>
+
+ <para>An exception is that objects using <literal>native</literal>
ID
+ generation are inserted when they are saved.</para>
+
+ <para>Except when you explicitly <literal>flush()</literal>, there
are
+ absolutely no guarantees about <emphasis>when</emphasis> the
+ <literal>Session</literal> executes the JDBC calls, only the
+ <emphasis>order</emphasis> in which they are executed. However,
Hibernate
+ does guarantee that the <literal>Query.list(..)</literal> will never
+ return stale or incorrect data.</para>
+
+ <para>It is possible to change the default behavior so that flush occurs
+ less frequently. The <literal>FlushMode</literal> class defines three
+ different modes: only flush at commit time when the Hibernate
+ <literal>Transaction</literal> API is used, flush automatically using
the
+ explained routine, or never flush unless <literal>flush()</literal> is
+ called explicitly. The last mode is useful for long running units of work,
+ where a <literal>Session</literal> is kept open and disconnected for a
+ long time (see <xref
+ linkend="transactions-optimistic-longsession" />).</para>
+
+ <programlisting role="JAVA">sess = sf.openSession();
Transaction tx = sess.beginTransaction();
sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
@@ -1090,188 +947,245 @@
// change to izi is not flushed!
...
tx.commit(); // flush occurs
-sess.close();]]></programlisting>
+sess.close();</programlisting>
- <para>
- During flush, an exception might occur (e.g. if a DML operation violates a
constraint).
- Since handling exceptions involves some understanding of Hibernate's
transactional
- behavior, we discuss it in <xref linkend="transactions"/>.
- </para>
+ <para>During flush, an exception might occur (e.g. if a DML operation
+ violates a constraint). Since handling exceptions involves some
+ understanding of Hibernate's transactional behavior, we discuss it in
+ <xref linkend="transactions" />.</para>
+ </section>
- </section>
+ <section id="objectstate-transitive" revision="1">
+ <title>Transitive persistence</title>
- <section id="objectstate-transitive" revision="1">
- <title>Transitive persistence</title>
+ <para>It is quite cumbersome to save, delete, or reattach individual
+ objects, especially if you deal with a graph of associated objects. A
+ common case is a parent/child relationship. Consider the following
+ example:</para>
- <para>
- It is quite cumbersome to save, delete, or reattach individual objects,
- especially if you deal with a graph of associated objects. A common case is
- a parent/child relationship. Consider the following example:
- </para>
+ <para>If the children in a parent/child relationship would be value typed
+ (e.g. a collection of addresses or strings), their life cycle would depend
+ on the parent and no further action would be required for convenient
+ "cascading" of state changes. When the parent is saved, the value-typed
+ child objects are saved and when the parent is deleted, the children will
+ be deleted, etc. This works for operations such as the removal of a child
+ from the collection. Since value-typed objects cannot have shared
+ references, Hibernate will detect this and delete the child from the
+ database.</para>
- <para>
- If the children in a parent/child relationship would be value typed (e.g. a
collection
- of addresses or strings), their life cycle would depend on the parent and no
- further action would be required for convenient "cascading" of
state changes.
- When the parent is saved, the value-typed child objects are saved and
- when the parent is deleted, the children will be deleted, etc. This
- works for operations such as the removal of a child from the collection.
- Since value-typed objects cannot have shared
- references, Hibernate will detect this and delete the child from the
database.
- </para>
+ <para>Now consider the same scenario with parent and child objects being
+ entities, not value-types (e.g. categories and items, or parent and child
+ cats). Entities have their own life cycle and support shared references.
+ Removing an entity from the collection does not mean it can be deleted),
+ and there is by default no cascading of state from one entity to any other
+ associated entities. Hibernate does not implement <emphasis>persistence by
+ reachability</emphasis> by default.</para>
- <para>
- Now consider the same scenario with parent and child objects being entities,
- not value-types (e.g. categories and items, or parent and child cats).
Entities
- have their own life cycle and support shared references. Removing an entity
from
- the collection does not mean it can be deleted), and there is by default no
- cascading of state from one entity to any other associated entities.
Hibernate
- does not implement <emphasis>persistence by
reachability</emphasis> by default.
- </para>
+ <para>For each basic operation of the Hibernate session - including
+ <literal>persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(),
+ evict(), replicate()</literal> - there is a corresponding cascade style.
+ Respectively, the cascade styles are named <literal>create, merge,
+ save-update, delete, lock, refresh, evict, replicate</literal>. If you
+ want an operation to be cascaded along an association, you must indicate
+ that in the mapping document. For example:</para>
- <para>
- For each basic operation of the Hibernate session - including
<literal>persist(), merge(),
- saveOrUpdate(), delete(), lock(), refresh(), evict(),
replicate()</literal> - there is a
- corresponding cascade style. Respectively, the cascade styles are named
<literal>create,
- merge, save-update, delete, lock, refresh, evict, replicate</literal>.
If you want an
- operation to be cascaded along an association, you must indicate that in the
mapping
- document. For example:
- </para>
-
- <programlisting role="XML"><![CDATA[<one-to-one
name="person" cascade="persist"/>]]></programlisting>
-
- <para>
- Cascade styles my be combined:
- </para>
-
- <programlisting role="XML"><![CDATA[<one-to-one
name="person"
cascade="persist,delete,lock"/>]]></programlisting>
-
- <para>
- You can even use <literal>cascade="all"</literal> to
specify that <emphasis>all</emphasis>
- operations should be cascaded along the association. The default
<literal>cascade="none"</literal>
- specifies that no operations are to be cascaded.
- </para>
-
- <para>
- A special cascade style, <literal>delete-orphan</literal>,
applies only to one-to-many
- associations, and indicates that the <literal>delete()</literal>
operation should
- be applied to any child object that is removed from the association.
- </para>
+ <programlisting role="XML"><one-to-one name="person"
cascade="persist"/></programlisting>
+ <para>Cascade styles my be combined:</para>
- <para>
- Recommendations:
- </para>
+ <programlisting role="XML"><one-to-one name="person"
cascade="persist,delete,lock"/></programlisting>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- It does not usually make sense to enable cascade on a
<literal><many-to-one></literal>
- or <literal><many-to-many></literal>
association. Cascade is often useful for
- <literal><one-to-one></literal> and
<literal><one-to-many></literal>
- associations.
- </para>
- </listitem>
- <listitem>
- <para>
- If the child object's lifespan is bounded by the lifespan of the
parent
- object, make it a <emphasis>life cycle object</emphasis>
by specifying
-
<literal>cascade="all,delete-orphan"</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Otherwise, you might not need cascade at all. But if you think that
you will often be
- working with the parent and children together in the same
transaction, and you want to save
- yourself some typing, consider using
<literal>cascade="persist,merge,save-update"</literal>.
- </para>
- </listitem>
- </itemizedlist>
+ <para>You can even use <literal>cascade="all"</literal>
to specify that
+ <emphasis>all</emphasis> operations should be cascaded along the
+ association. The default <literal>cascade="none"</literal>
specifies that
+ no operations are to be cascaded.</para>
- <para>
- Mapping an association (either a single valued association, or a collection)
with
- <literal>cascade="all"</literal> marks the association
as a
- <emphasis>parent/child</emphasis> style relationship where
save/update/delete of the
- parent results in save/update/delete of the child or children.
- </para>
- <para>
- Furthermore, a mere reference to a child from a persistent parent will result
in
- save/update of the child. This metaphor is incomplete, however. A child which
becomes
- unreferenced by its parent is <emphasis>not</emphasis>
automatically deleted, except
- in the case of a <literal><one-to-many></literal>
association mapped with
- <literal>cascade="delete-orphan"</literal>. The precise
semantics of cascading
- operations for a parent/child relationship are as follows:
- </para>
+ <para>In case you are using annotatons you probably have noticed the
+ <literal>cascade</literal> attribute taking an array of
+ <classname>CascadeType</classname> as a value. The cascade concept in
JPA
+ is very is similar to the transitive persistence and cascading of
+ operations as described above, but with slightly different semantics and
+ cascading types:</para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- If a parent is passed to <literal>persist()</literal>,
all children are passed to
- <literal>persist()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is passed to <literal>merge()</literal>, all
children are passed to
- <literal>merge()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is passed to <literal>save()</literal>,
<literal>update()</literal> or
- <literal>saveOrUpdate()</literal>, all children are
passed to <literal>saveOrUpdate()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a transient or detached child becomes referenced by a persistent
parent,
- it is passed to <literal>saveOrUpdate()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is deleted, all children are passed to
<literal>delete()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a child is dereferenced by a persistent parent,
<emphasis>nothing
- special happens</emphasis> - the application should explicitly
delete
- the child if necessary - unless
<literal>cascade="delete-orphan"</literal>,
- in which case the "orphaned" child is deleted.
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para><literal>CascadeType.PERSIST</literal>: cascades the
persist
+ (create) operation to associated entities persist() is called or if
+ the entity is managed</para>
+ </listitem>
- <para>
- Finally, note that cascading of operations can be applied to an object graph
at
- <emphasis>call time</emphasis> or at <emphasis>flush
time</emphasis>. All operations,
- if enabled, are cascaded to associated entities reachable when the operation
is
- executed. However, <literal>save-update</literal> and
<literal>delete-orphan</literal>
- are transitive for all associated entities reachable during flush of the
- <literal>Session</literal>.
- </para>
+ <listitem>
+ <para><literal>CascadeType.MERGE</literal>: cascades the merge
+ operation to associated entities if merge() is called or if the entity
+ is managed</para>
+ </listitem>
- </section>
+ <listitem>
+ <para><literal>CascadeType.REMOVE</literal>: cascades the
remove
+ operation to associated entities if delete() is called</para>
+ </listitem>
- <section id="objectstate-metadata">
- <title>Using metadata</title>
+ <listitem>
+ <para><literal>CascadeType.REFRESH:</literal> cascades the
refresh
+ operation to associated entities if refresh() is called</para>
+ </listitem>
- <para>
- Hibernate requires a rich meta-level model of all entity and value types.
- This model can be useful to the application itself. For example, the
application
- might use Hibernate's metadata to implement a "smart" deep-copy
algorithm that understands
- which objects should be copied (eg. mutable value types) and which objects
that should not (e.g.
- immutable value types and, possibly, associated entities).
- </para>
- <para>
- Hibernate exposes metadata via the
<literal>ClassMetadata</literal> and
- <literal>CollectionMetadata</literal> interfaces and the
<literal>Type</literal>
- hierarchy. Instances of the metadata interfaces can be obtained from the
- <literal>SessionFactory</literal>.
- </para>
+ <listitem>
+ <para><literal>CascadeType.DETACH:</literal> cascades the
detach
+ operation to associated entities if detach() is called</para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[Cat fritz = ......;
+ <listitem>
+ <para><literal>CascadeType.ALL</literal>: all of the
above</para>
+ </listitem>
+ </itemizedlist>
+
+ <note>
+ <para>CascadeType.ALL also covers Hibernate specific operations like
+ save-update, lock etc... </para>
+ </note>
+
+ <para>A special cascade style, <literal>delete-orphan</literal>,
applies
+ only to one-to-many associations, and indicates that the
+ <literal>delete()</literal> operation should be applied to any child
+ object that is removed from the association. Using annotations there is no
+ <literal>CascadeType.DELETE-ORPHAN</literal> equivalent. Instead you can
+ use the attribute <literal>orphanRemoval as seen in </literal><xref
+ linkend="example-one-to-many-with-orphan-removal" />. If an entity is
+ removed from a <classname>@OneToMany</classname> collection or an
+ associated entity is dereferenced from a
<classname>@OneToOne</classname>
+ association, this associated entity can be marked for deletion if
+ <literal>orphanRemoval</literal> is set to true.</para>
+
+ <example id="example-one-to-many-with-orphan-removal">
+ <title><literal>@OneToMany</literal> with
+ <literal>orphanRemoval</literal></title>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+public class Customer {
+ private Set<Order> orders;
+
+ @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
+ public Set<Order> getOrders() { return orders; }
+
+ public void setOrders(Set<Order> orders) { this.orders = orders; }
+
+ [...]
+}
+
+@Entity
+public class Order { ... }
+
+Customer customer = em.find(Customer.class, 1l);
+Order order = em.find(Order.class, 1l);
+customer.getOrders().remove(order); //order will be deleted by
cascade</programlisting>
+ </example>
+
+ <para>Recommendations:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>It does not usually make sense to enable cascade on a
+ many-to-one or many-to-many association. In fact the
+ <literal>@ManyToOne</literal> and
<literal>@ManyToMany</literal> don't
+ even offer a <literal>orphanRemoval</literal> attribute. Cascading
is
+ often useful for one-to-one and one-to-many associations.</para>
+ </listitem>
+
+ <listitem>
+ <para>If the child object's lifespan is bounded by the lifespan of the
+ parent object, make it a <emphasis>life cycle object</emphasis> by
+ specifying
+
<literal>cascade="all,delete-orphan"(<literal>(a)OneToMany(cascade=CascadeType.ALL,
+ orphanRemoval=true)</literal>)</literal>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Otherwise, you might not need cascade at all. But if you think
+ that you will often be working with the parent and children together
+ in the same transaction, and you want to save yourself some typing,
+ consider using
+
<literal>cascade="persist,merge,save-update"</literal>.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Mapping an association (either a single valued association, or a
+ collection) with <literal>cascade="all"</literal> marks the
association as
+ a <emphasis>parent/child</emphasis> style relationship where
+ save/update/delete of the parent results in save/update/delete of the
+ child or children.</para>
+
+ <para>Furthermore, a mere reference to a child from a persistent parent
+ will result in save/update of the child. This metaphor is incomplete,
+ however. A child which becomes unreferenced by its parent is
+ <emphasis>not</emphasis> automatically deleted, except in the case of a
+ one-to-many association mapped with
+ <literal>cascade="delete-orphan"</literal>. The precise
semantics of
+ cascading operations for a parent/child relationship are as
+ follows:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>If a parent is passed to <literal>persist()</literal>,
all
+ children are passed to <literal>persist()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a parent is passed to <literal>merge()</literal>, all
+ children are passed to <literal>merge()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a parent is passed to <literal>save()</literal>,
+ <literal>update()</literal> or
<literal>saveOrUpdate()</literal>, all
+ children are passed to
<literal>saveOrUpdate()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a transient or detached child becomes referenced by a
+ persistent parent, it is passed to
+ <literal>saveOrUpdate()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a parent is deleted, all children are passed to
+ <literal>delete()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a child is dereferenced by a persistent parent,
+ <emphasis>nothing special happens</emphasis> - the application
should
+ explicitly delete the child if necessary - unless
+ <literal>cascade="delete-orphan"</literal>, in which case
the
+ "orphaned" child is deleted.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Finally, note that cascading of operations can be applied to an
+ object graph at <emphasis>call time</emphasis> or at
<emphasis>flush
+ time</emphasis>. All operations, if enabled, are cascaded to associated
+ entities reachable when the operation is executed. However,
+ <literal>save-update</literal> and
<literal>delete-orphan</literal> are
+ transitive for all associated entities reachable during flush of the
+ <literal>Session</literal>.</para>
+ </section>
+
+ <section id="objectstate-metadata">
+ <title>Using metadata</title>
+
+ <para>Hibernate requires a rich meta-level model of all entity and value
+ types. This model can be useful to the application itself. For example,
+ the application might use Hibernate's metadata to implement a "smart"
+ deep-copy algorithm that understands which objects should be copied (eg.
+ mutable value types) and which objects that should not (e.g. immutable
+ value types and, possibly, associated entities).</para>
+
+ <para>Hibernate exposes metadata via the
<literal>ClassMetadata</literal>
+ and <literal>CollectionMetadata</literal> interfaces and the
+ <literal>Type</literal> hierarchy. Instances of the metadata interfaces
+ can be obtained from the <literal>SessionFactory</literal>.</para>
+
+ <programlisting role="JAVA">Cat fritz = ......;
ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
Object[] propertyValues = catMeta.getPropertyValues(fritz);
@@ -1280,13 +1194,10 @@
// get a Map of all properties which are not collections or associations
Map namedValues = new HashMap();
-for ( int i=0; i<propertyNames.length; i++ ) {
- if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType()
) {
+for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( !propertyTypes[i].isEntityType() &&
!propertyTypes[i].isCollectionType() ) {
namedValues.put( propertyNames[i], propertyValues[i] );
}
-}]]></programlisting>
-
- </section>
-
+}</programlisting>
+ </section>
</chapter>
-