HHH-6082 - Incorporate EntityManager documentation into main dev guide

This commit is contained in:
Steve Ebersole 2012-02-07 00:21:10 -06:00
parent 591364409e
commit 30deb20ff1
85 changed files with 1127 additions and 5895 deletions

View File

@ -16,9 +16,9 @@
<xi:include href="Data_Categorizations.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="Mapping_Entities.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="Mapping_Association.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="chapters/hql/HQL_JPQL.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="chapters/criteria/Criteria.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="chapters/native-sql/Native_SQL.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="chapters/query_ql/HQL_JPQL.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="chapters/query_criteria/Criteria.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="chapters/query_native/Native_SQL.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="JMX.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="Envers.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="chapters/multi_tenancy/Multi_Tenancy.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />

View File

@ -1,18 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!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_Development_Guide.ent">
%BOOK_ENTITIES;
]>
<chapter>
<title>Native SQL Queries</title>
<para>
You may also express queries in the native SQL dialect of your database. This is useful if you
want to utilize database specific features such as query hints or the CONNECT BY option in Oracle.
It also provides a clean migration path from a direct SQL/JDBC based application to Hibernate/JPA.
Hibernate also allows you to specify handwritten SQL (including stored procedures) for all
create, update, delete, and load operations.
</para>
</chapter>

View File

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2010, Red Hat Inc. or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY version "WORKING">
<!ENTITY today "TODAY">
]>
<book>
<bookinfo>
<title>Hibernate EntityManager</title>
<subtitle>User guide</subtitle>
<releaseinfo>&version;</releaseinfo>
<edition>1.0</edition>
<pubsnumber>1</pubsnumber>
<pubdate>&today;</pubdate>
<productnumber>&version;</productnumber>
<issuenum>1</issuenum>
<mediaobject>
<imageobject>
<imagedata fileref="images/hibernate_logo_a.png" format="PNG" />
</imageobject>
</mediaobject>
<copyright>
<year>2005</year>
<holder>Red Hat Inc. and the various authors</holder>
</copyright>
<authorgroup>
<author>
<firstname>Emmanuel</firstname>
<surname>Bernard</surname>
</author>
<author>
<firstname>Steve</firstname>
<surname>Ebersole</surname>
</author>
<author>
<firstname>Gavin</firstname>
<surname>King</surname>
</author>
<!--TODO add translators like core did -->
</authorgroup>
</bookinfo>
<toc></toc>
<preface>
<title>Introducing JPA Persistence</title>
<para>The JPA specification recognizes the interest and the success of the
transparent object/relational mapping paradigm. It standardizes the basic
APIs and the metadata needed for any object/relational persistence
mechanism. <emphasis>Hibernate EntityManager</emphasis> implements the
programming interfaces and lifecycle rules as defined by the JPA 2.0
specification. Together with <emphasis>Hibernate Annotations</emphasis>,
this wrapper implements a complete (and standalone) JPA persistence
solution on top of the mature Hibernate Core. You may use a combination of
all three together, annotations without JPA programming interfaces and
lifecycle, or even pure native Hibernate Core, depending on the business
and technical needs of your project. You can at all times fall back to
Hibernate native APIs, or if required, even to native JDBC and SQL.</para>
</preface>
<xi:include href="modules/non-migrated/architecture.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/migrated/configuration.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/migrated/entitymanagerapi.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/non-migrated/metamodel.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/migrated/transactions.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/migrated/listeners.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/migrated/batch.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/migrated/query_ejbql.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/migrated/query_criteria.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="modules/query_native.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<bibliography>
<title>References</title>
<biblioentry id="JPA2">
<abbrev id="JPA2_ABBREV">JPA 2 Specification</abbrev>
<title>JSR 317: <trademark>Java</trademark> Persistence API, Version
2.0</title>
<collab>
<collabname>Java Persistence 2.0 Expert Group</collabname>
</collab>
<copyright>
<year>2009</year>
<holder>SUN MICROSYSTEMS, INC.</holder>
</copyright>
<bibliomisc><email>jsr-317-feedback@sun.com</email> <ulink
url="http://jcp.org/en/jsr/detail?id=317">JSR 317 JCP
Page</ulink></bibliomisc>
</biblioentry>
</bibliography>
</book>

View File

@ -1,115 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Inc or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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">
<chapter id="batch">
<title>Batch processing</title>
<para>Batch processing has traditionally been difficult in full
object/relational mapping. ORM is all about object state management, which
implies that object state is available in memory. However, Hibernate has
some features to optimize batch processing which are discussed in the
Hibernate reference guide, however, EJB3 persistence differs
slightly.</para>
<section id="batch-direct">
<title>Bulk update/delete</title>
<para>As already discussed, automatic and transparent object/relational
mapping is concerned with the management of object state. This implies
that the object state is available in memory, hence updating or deleting
(using SQL <literal>UPDATE</literal> and <literal>DELETE</literal>) data
directly in the database will not affect in-memory state. However,
Hibernate provides methods for bulk SQL-style <literal>UPDATE</literal>
and <literal>DELETE</literal> statement execution which are performed
through JP-QL (<xref linkend="queryhql" />).</para>
<para>The pseudo-syntax for <literal>UPDATE</literal> and
<literal>DELETE</literal> statements is: <literal>( UPDATE | DELETE )
FROM? ClassName (WHERE WHERE_CONDITIONS)?</literal>. Note that:</para>
<itemizedlist spacing="compact">
<listitem>
<para>In the from-clause, the FROM keyword is optional.</para>
</listitem>
<listitem>
<para>There can only be a single class named in the from-clause, and
it <emphasis>cannot</emphasis> have an alias (this is a current
Hibernate limitation and will be removed soon).</para>
</listitem>
<listitem>
<para>No joins (either implicit or explicit) can be specified in a
bulk JP-QL query. Sub-queries may be used in the where-clause.</para>
</listitem>
<listitem>
<para>The where-clause is also optional.</para>
</listitem>
</itemizedlist>
<para>As an example, to execute an JP-QL <literal>UPDATE</literal>, use
the <literal>Query.executeUpdate()</literal> method:</para>
<programlisting role="JAVA" language="JAVA">EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
String jpqlUpdate = "update Customer set name = :newName where name = :oldName"
int updatedEntities = entityManager.createQuery( jpqlUpdate )
.setParameter( "newName", newName )
.setParameter( "oldName", oldName )
.executeUpdate();
entityManager.getTransaction().commit();
entityManager.close();</programlisting>
<para>To execute an JP-QL <literal>DELETE</literal>, use the same
<literal>Query.executeUpdate()</literal> method (the method is named for
those familiar with JDBC's
<literal>PreparedStatement.executeUpdate()</literal>):</para>
<programlisting role="JAVA" language="JAVA">EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = entityManager.createQuery( hqlDelete )
.setParameter( "oldName", oldName )
.executeUpdate();
entityManager.getTransaction().commit();
entityManager.close();</programlisting>
<para>The <literal>int</literal> value returned by the
<literal>Query.executeUpdate()</literal> method indicate the number of
entities effected by the operation. This may or may not correlate with the
number of rows effected in the database. A JP-QL bulk operation might
result in multiple actual SQL statements being executed, for
joined-subclass, for example. The returned number indicates the number of
actual entities affected by the statement. Going back to the example of
joined-subclass, a delete against one of the subclasses may actually
result in deletes against not just the table to which that subclass is
mapped, but also the "root" table and potentially joined-subclass tables
further down the inheritance hierarchy.</para>
</section>
</chapter>

View File

@ -1,265 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Inc or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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">
<chapter id="listeners">
<title>Entity listeners and Callback methods</title>
<section>
<title>Definition</title>
<para>It is often useful for the application to react to certain events
that occur inside the persistence mechanism. This allows the
implementation of certain kinds of generic functionality, and extension of
built-in functionality. The JPA specification provides two related
mechanisms for this purpose.</para>
<para>A method of the entity may be designated as a callback method to
receive notification of a particular entity life cycle event. Callbacks
methods are annotated by a callback annotation. You can also define an
entity listener class to be used instead of the callback methods defined
directly inside the entity class. An entity listener is a stateless class
with a no-arg constructor. An entity listener is defined by annotating the
entity class with the <literal>@EntityListeners</literal>
annotation:</para>
<programlisting role="JAVA" language="JAVA">@Entity
@EntityListeners(class=Audit.class)
public class Cat {
@Id private Integer id;
private String name;
private Calendar dateOfBirth;
@Transient private int age;
private Date lastUpdate;
//getters and setters
/**
* Set my transient property at load time based on a calculation,
* note that a native Hibernate formula mapping is better for this purpose.
*/
@PostLoad
public void calculateAge() {
Calendar birth = new GregorianCalendar();
birth.setTime(dateOfBirth);
Calendar now = new GregorianCalendar();
now.setTime( new Date() );
int adjust = 0;
if ( now.get(Calendar.DAY_OF_YEAR) - birth.get(Calendar.DAY_OF_YEAR) &lt; 0) {
adjust = -1;
}
age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR) + adjust;
}
}
public class LastUpdateListener {
/**
* automatic property set before any database persistence
*/
@PreUpdate
@PrePersist
public void setLastUpdate(Cat o) {
o.setLastUpdate( new Date() );
}
}</programlisting>
<para>The same callback method or entity listener method can be annotated
with more than one callback annotation. For a given entity, you cannot
have two methods being annotated by the same callback annotation whether
it is a callback method or an entity listener method. A callback method is
a no-arg method with no return type and any arbitrary name. An entity
listener has the signature <code>void &lt;METHOD&gt;(Object)</code> where
Object is of the actual entity type (note that Hibernate Entity Manager
relaxed this constraint and allows <literal>Object</literal> of
<literal>java.lang.Object</literal> type (allowing sharing of listeners
across several entities.)</para>
<para>A callback method can raise a
<classname>RuntimeException</classname>. The current transaction, if any,
must be rolled back. The following callbacks are defined:</para>
<table>
<title>Callbacks</title>
<tgroup cols="2">
<thead>
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="3*" />
<row>
<entry align="center">Type</entry>
<entry align="center">Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>@PrePersist</entry>
<entry>Executed before the entity manager persist operation is
actually executed or cascaded. This call is synchronous with the
persist operation.</entry>
</row>
<row>
<entry>@PreRemove</entry>
<entry>Executed before the entity manager remove operation is
actually executed or cascaded. This call is synchronous with the
remove operation.</entry>
</row>
<row>
<entry>@PostPersist</entry>
<entry>Executed after the entity manager persist operation is
actually executed or cascaded. This call is invoked after the
database INSERT is executed.</entry>
</row>
<row>
<entry>@PostRemove</entry>
<entry>Executed after the entity manager remove operation is
actually executed or cascaded. This call is synchronous with the
remove operation.</entry>
</row>
<row>
<entry>@PreUpdate</entry>
<entry>Executed before the database UPDATE operation.</entry>
</row>
<row>
<entry>@PostUpdate</entry>
<entry>Executed after the database UPDATE operation.</entry>
</row>
<row>
<entry>@PostLoad</entry>
<entry>Executed after an entity has been loaded into the current
persistence context or an entity has been refreshed.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>A callback method must not invoke
<classname>EntityManager</classname> or <classname>Query</classname>
methods!</para>
</section>
<section>
<title>Callbacks and listeners inheritance</title>
<para>You can define several entity listeners per entity at different
level of the hierarchy. You can also define several callbacks at different
level of the hierarchy. But you cannot define two listeners for the same
event in the same entity or the same entity listener.</para>
<para>When an event is raised, the listeners are executed in this
order:</para>
<itemizedlist>
<listitem>
<para><literal>@EntityListeners</literal> for a given entity or
superclass in the array order</para>
</listitem>
<listitem>
<para>Entity listeners for the superclasses (highest first)</para>
</listitem>
<listitem>
<para>Entity Listeners for the entity</para>
</listitem>
<listitem>
<para>Callbacks of the superclasses (highest first)</para>
</listitem>
<listitem>
<para>Callbacks of the entity</para>
</listitem>
</itemizedlist>
<para>You can stop the entity listeners inheritance by using the
<literal>@ExcludeSuperclassListeners</literal>, all superclasses
<literal>@EntityListeners</literal> will then be ignored.</para>
</section>
<section>
<title>XML definition</title>
<para>The JPA specification allows annotation overriding through JPA
deployment descriptors. There is also an additional feature that can be
useful: default event listeners.</para>
<programlisting role="XML" language="XML">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0"
&gt;
&lt;persistence-unit-metadata&gt;
&lt;persistence-unit-defaults&gt;
&lt;entity-listeners&gt;
&lt;entity-listener class="org.hibernate.ejb.test.pack.defaultpar.IncrementListener"&gt;
&lt;pre-persist method-name="increment"/&gt;
&lt;/entity-listener&gt;
&lt;/entity-listeners&gt;
&lt;/persistence-unit-defaults&gt;
&lt;/persistence-unit-metadata&gt;
&lt;package&gt;org.hibernate.ejb.test.pack.defaultpar&lt;/package&gt;
&lt;entity class="ApplicationServer"&gt;
&lt;entity-listeners&gt;
&lt;entity-listener class="OtherIncrementListener"&gt;
&lt;pre-persist method-name="increment"/&gt;
&lt;/entity-listener&gt;
&lt;/entity-listeners&gt;
&lt;pre-persist method-name="calculate"/&gt;
&lt;/entity&gt;
&lt;/entity-mappings&gt;</programlisting>
<para>You can override entity listeners on a given entity. An entity
listener correspond to a given class and one or several event fire a given
method call. You can also define event on the entity itself to describe
the callbacks.</para>
<para>Last but not least, you can define some default entity listeners
that will apply first on the entity listener stack of all the mapped
entities of a given persistence unit. If you don't want an entity to
inherit the default listeners, you can use
<classname>@ExcludeDefaultListeners</classname> (or
&lt;exclude-default-listeners/&gt;).</para>
</section>
</chapter>

View File

@ -1,736 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2010, Red Hat Inc. or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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">
<chapter id="querycriteria">
<title>Criteria Queries</title>
<para>Criteria queries are a programmatic, type-safe way to express a query.
They are type-safe in terms of using interfaces and classes to represent
various structural parts of a query such as the query itself, or the select
clause, or an order-by, etc. They can also be type-safe in terms of
referencing attributes as we will see in a bit. Users of the older Hibernate
<interfacename>org.hibernate.Criteria</interfacename> query API will
recognize the general approach, though we believe the JPA API to be superior
as it represents a clean look at the lessons learned from that API.</para>
<para>Criteria queries are essentially an object graph, where each part of
the graph represents an increasing (as we navigate down this graph) more
atomic part of query. The first step in performing a criteria query is
building this graph. The
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
interface is the first thing with which you need to become acquainted to
begin using criteria queries. Its role is that of a factory for all the
individual pieces of the criteria. You obtain a
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
instance by calling the <methodname>getCriteriaBuilder</methodname> method
of the
<interfacename>javax.persistence.EntityManagerFactory</interfacename></para>
<programlisting role="JAVA" language="JAVA">CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder();</programlisting>
<para>The next step is to obtain a
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. You
do this by one of the 3 methods on
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
for this purpose.</para>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;T&gt; createQuery(Class&lt;T&gt;)</programlisting>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;Tuple&gt; createTupleQuery()</programlisting>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;Object&gt; createQuery()</programlisting>
<para>Each serves a different purpose depending on the expected type of the
query results.</para>
<note>
<para><citetitle pubwork="chapter">Chapter 6 Criteria API</citetitle> of
the <citation><xref linkend="JPA2" /></citation> already contains a decent
amount of reference material pertaining to the various parts of a criteria
query. So rather than duplicate all that content here, lets instead look
at some of the more widely anticipated usages of the API.</para>
</note>
<section id="querycriteria-typedquery">
<title>Typed criteria queries</title>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;T&gt; createQuery(Class&lt;T&gt;)</programlisting>
<para>The type of the criteria query (aka the &lt;T&gt;) indicates the
expected types in the query result. This might be an entity, an Integer,
or any other object.</para>
<section id="querycriteria-typedquery-entity">
<title>Selecting an entity</title>
<para>This the most used form of query in Hibernate Query Language (HQL)
and Hibernate Criteria Queries. You have an entity and you want to
select one or more of that entity based on some condition.</para>
<example id="ex-criteria-typedquery-entity">
<title>Selecting the root entity</title>
<programlistingco role="JAVA">
<areaspec>
<areaset coords="" id="ex.criteria.typedquery.entity.1">
<area coords="1" id="ex.criteria.typedquery.entity.1.c1" />
<area coords="6" id="ex.criteria.typedquery.entity.1.c2" />
</areaset>
<area coords="3" id="ex.criteria.typedquery.entity.2" />
<area coords="4" id="ex.criteria.typedquery.entity.3" />
</areaspec>
<programlisting>CriteriaQuery&lt;Person&gt; criteria = builder.createQuery( Person.class );
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
criteria.select( personRoot );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List&lt;Person&gt; people = em.createQuery( criteria ).getResultList();
for ( Person person : people ) { ... }</programlisting>
</programlistingco>
<calloutlist>
<callout arearefs="ex.criteria.typedquery.entity.1">
<para>We use the form <emphasis>createQuery( Person.class
)</emphasis> here because the expected returns are in fact Person
entities as we see when we begin processing the results.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.entity.2">
<para><emphasis>personCriteria.select( personRoot )</emphasis>
here is completely unneeded in this specific case because of the
fact that <emphasis>personRoot</emphasis> will be the implied
selection since we have only a single root. It was done here only
for completeness of an example</para>
</callout>
<callout arearefs="ex.criteria.typedquery.entity.3">
<para><emphasis>Person_.eyeColor</emphasis> is an example of the
static form of metamodel reference. We will use that form
exclusively in this chapter. See <xref
linkend="metamodel-static" /> for details.</para>
</callout>
</calloutlist>
</example>
</section>
<section id="querycriteria-typedquery-expression">
<title>Selecting a value</title>
<para>The simplest form of selecting a value is selecting a particular
attribute from an entity. But this might also be an aggregation, a
mathematical operation, etc.</para>
<example id="ex-criteria-typedquery-attribute">
<title>Selecting an attribute</title>
<programlistingco role="JAVA">
<areaspec>
<areaset coords="" id="ex.criteria.typedquery.attr.1">
<area coords="1" id="ex.criteria.typedquery.attr.1.c1" />
<area coords="5" id="ex.criteria.typedquery.attr.1.c2" />
</areaset>
<area coords="3" id="ex.criteria.typedquery.attr.2" />
</areaspec>
<programlisting>CriteriaQuery&lt;Integer&gt; criteria = builder.createQuery( Integer.class );
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
criteria.select( personRoot.get( Person_.age ) );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List&lt;Integer&gt; ages = em.createQuery( criteria ).getResultList();
for ( Integer age : ages ) { ... } </programlisting>
</programlistingco>
<calloutlist>
<callout arearefs="ex.criteria.typedquery.attr.1">
<para>Notice again the typing of the query based on the
anticipated result type(s). Here we are specifying
<classname>java.lang.Integer</classname> as the type of the
<emphasis>Person#age</emphasis> attribute is
<classname>java.lang.Integer</classname>.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.attr.2">
<para>We need to bind the fact that we are interested in the age
associated with the <emphasis>personRoot</emphasis>. We might have
multiple references to the Person entity in the query so we need
to identify (aka qualify) which <emphasis>Person#age</emphasis> we
mean.</para>
</callout>
</calloutlist>
</example>
<example id="ex-criteria-typedquery-expression">
<title>Selecting an expression</title>
<programlistingco role="JAVA">
<areaspec>
<area coords="3" id="ex.criteria.typedquery.expr.1" />
</areaspec>
<programlisting>CriteriaQuery&lt;Integer&gt; criteria = builder.createQuery( Integer.class );
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
criteria.select( builder.max( personRoot.get( Person_.age ) ) );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
Integer maxAge = em.createQuery( criteria ).getSingleResult();</programlisting>
</programlistingco>
<calloutlist>
<callout arearefs="ex.criteria.typedquery.expr.1">
<para>Here we see
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
used to obtain a <emphasis>MAX</emphasis> expression. These
expression building methods return
<interfacename>javax.persistence.criteria.Expression</interfacename>
instances typed according to various rules. The rule for a
<emphasis>MAX</emphasis> expression is that the expression type is
the same as that of the underlying attribute.</para>
</callout>
</calloutlist>
</example>
</section>
<section id="querycriteria-typedquery-multiselect">
<title>Selecting multiple values</title>
<para>There are actually a few different ways to select multiple values
using criteria queries. We will explore 2 options here, but an
alternative recommended approach is to use tuples as described in <xref
linkend="querycriteria-tuple" /></para>
<example id="ex-criteria-typedquery-array">
<title>Selecting an array</title>
<programlistingco role="JAVA">
<areaspec>
<areaset coords="" id="ex.criteria.typedquery.array.1">
<area coords="1" id="ex.criteria.typedquery.array.1.c1" />
<area coords="7" id="ex.criteria.typedquery.array.1.c2" />
</areaset>
<area coords="5" id="ex.criteria.typedquery.array.2" />
</areaspec>
<programlisting>CriteriaQuery&lt;Object[]&gt; criteria = builder.createQuery( Object[].class );
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
Path&lt;Long&gt; idPath = personRoot.get( Person_.id );
Path&lt;Integer&gt; agePath = personRoot.get( Person_.age );
criteria.select( builder.array( idPath, agePath ) );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List&lt;Object[]&gt; valueArray = em.createQuery( criteria ).getResultList();
for ( Object[] values : valueArray ) {
final Long id = (Long) values[0];
final Integer age = (Integer) values[1];
...
}</programlisting>
</programlistingco>
<calloutlist>
<callout arearefs="ex.criteria.typedquery.array.1">
<para>Technically this is classified as a typed query, but as you
can see in handling the results that is sort of misleading.
Anyway, the expected result type here is an array.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.array.2">
<para>Here we see the use of the <methodname>array</methodname>
method of the
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
which explicitly combines individual selections into a
<interfacename>javax.persistence.criteria.CompoundSelection</interfacename>.</para>
</callout>
</calloutlist>
</example>
<example id="ex-criteria-typedquery-array2">
<title>Selecting an array (2)</title>
<programlistingco role="JAVA">
<areaspec>
<areaset coords="" id="ex.criteria.typedquery.array2.1">
<area coords="1" id="ex.criteria.typedquery.array2.1.c1" />
<area coords="7" id="ex.criteria.typedquery.array2.1.c2" />
</areaset>
<area coords="5" id="ex.criteria.typedquery.array2.2" />
</areaspec>
<programlisting>CriteriaQuery&lt;Object[]&gt; criteria = builder.createQuery( Object[].class );
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
Path&lt;Long&gt; idPath = personRoot.get( Person_.id );
Path&lt;Integer&gt; agePath = personRoot.get( Person_.age );
criteria.multiselect( idPath, agePath );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List&lt;Object[]&gt; valueArray = em.createQuery( criteria ).getResultList();
for ( Object[] values : valueArray ) {
final Long id = (Long) values[0];
final Integer age = (Integer) values[1];
...
} </programlisting>
</programlistingco>
<calloutlist>
<callout arearefs="ex.criteria.typedquery.array2.1">
<para>Just as we saw in <xref
linkend="ex-criteria-typedquery-array" /> we have a "typed"
criteria query returning an Object array.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.array2.2">
<para>This actually functions exactly the same as what we saw in
<xref linkend="ex-criteria-typedquery-array" />. The
<methodname>multiselect</methodname> method behaves slightly
differently based on the type given when the criteria query was
first built, but in this case it says to select and return an
<emphasis>Object[]</emphasis>.</para>
</callout>
</calloutlist>
</example>
</section>
<section id="querycriteria-typedquery-construct">
<title>Selecting a wrapper</title>
<para>Another alternative to <xref
linkend="querycriteria-typedquery-multiselect" /> is to instead select
an object that will "wrap" the multiple values. Going back to the
example query there, rather than returning an array of
<emphasis>[Person#id, Person#age]</emphasis> instead declare a class
that holds these values and instead return that.</para>
<example id="ex-criteria-typedquery-construct">
<title>Selecting an wrapper</title>
<programlistingco role="JAVA">
<areaspec>
<areaset coords="" id="ex.criteria.typedquery.construct.1">
<area coords="1" id="ex.criteria.typedquery.construct.1.c1" />
<area coords="4" id="ex.criteria.typedquery.construct.1.c2" />
</areaset>
<areaset coords="" id="ex.criteria.typedquery.construct.2">
<area coords="11" id="ex.criteria.typedquery.construct.2.c1" />
<area coords="21" id="ex.criteria.typedquery.construct.2.c2" />
</areaset>
<areaset coords="" id="ex.criteria.typedquery.construct.3">
<area coords="13" id="ex.criteria.typedquery.construct.3.c1" />
<area coords="14" id="ex.criteria.typedquery.construct.3.c2" />
</areaset>
</areaspec>
<programlisting>public class PersonWrapper {
private final Long id;
private final Integer age;
public PersonWrapper(Long id, Integer age) {
this.id = id;
this.age = age;
}
...
}
...
CriteriaQuery&lt;PersonWrapper&gt; criteria = builder.createQuery( PersonWrapper.class );
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
criteria.select(
builder.construct(
PersonWrapper.class,
personRoot.get( Person_.id ),
personRoot.get( Person_.age )
)
);
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List&lt;PersonWrapper&gt; people = em.createQuery( criteria ).getResultList();
for ( PersonWrapper person : people ) { ... }</programlisting>
</programlistingco>
<calloutlist>
<callout arearefs="ex.criteria.typedquery.construct.1">
<para>First we see the simple definition of the wrapper object we
will be using to wrap our result values. Specifically notice the
constructor and its argument types.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.construct.2">
<para>Since we will be returning
<emphasis>PersonWrapper</emphasis> objects, we use
<emphasis>PersonWrapper</emphasis> as the type of our criteria
query.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.construct.3">
<para>Here we see another new
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
method, <methodname>construct</methodname>, which is used to
builder a wrapper expression. Basically for every row in the
result we are saying we would like a
<emphasis>PersonWrapper</emphasis> instantiated by the matching
constructor. This wrapper expression is then passed as the
select.</para>
</callout>
</calloutlist>
</example>
</section>
</section>
<section id="querycriteria-tuple">
<title>Tuple criteria queries</title>
<para>A better approach to <xref
linkend="querycriteria-typedquery-multiselect" /> is to either use a
wrapper (which we just saw in <xref
linkend="querycriteria-typedquery-construct" />) or using the
<interfacename>javax.persistence.Tuple</interfacename> contract.</para>
<example id="ex-criteria-typedquery-tuple">
<title>Selecting a tuple</title>
<programlistingco role="JAVA">
<areaspec>
<areaset coords="" id="ex.criteria.typedquery.tuple.1">
<area coords="1" id="ex.criteria.typedquery.tuple.1.c1" />
<area coords="7" id="ex.criteria.typedquery.tuple.1.c2" />
</areaset>
<area coords="5" id="ex.criteria.typedquery.tuple.2" />
<areaset coords="" id="ex.criteria.typedquery.tuple.3">
<area coords="9" id="ex.criteria.typedquery.tuple.3.c1" />
<area coords="10" id="ex.criteria.typedquery.tuple.3.c2" />
</areaset>
</areaspec>
<programlisting>CriteriaQuery&lt;Tuple&gt; criteria = builder.createTupleQuery();
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
Path&lt;Long&gt; idPath = personRoot.get( Person_.id );
Path&lt;Integer&gt; agePath = personRoot.get( Person_.age );
criteria.multiselect( idPath, agePath );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List&lt;Tuple&gt; tuples = em.createQuery( criteria ).getResultList();
for ( Tuple tuple : valueArray ) {
assert tuple.get( 0 ) == tuple.get( idPath );
assert tuple.get( 1 ) == tuple.get( agePath );
...
} </programlisting>
</programlistingco>
<calloutlist>
<callout arearefs="ex.criteria.typedquery.tuple.1">
<para>Here we see the use of a new
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>
building method, <methodname>createTupleQuery</methodname>. This is
exactly equivalent to calling <emphasis>builder.createQuery(
Tuple.class )</emphasis>. It signifies that we want to access the
results through the
<interfacename>javax.persistence.Tuple</interfacename>
contract.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.tuple.2">
<para>Again we see the use of the
<methodname>multiselect</methodname> method, just like in <xref
linkend="ex-criteria-typedquery-array2" />. The difference here is
that the type of the
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>
was defined as
<interfacename>javax.persistence.Tuple</interfacename> so the
compound selections in this case are interpreted to be the tuple
elements.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.tuple.3">
<para>Here we see
<interfacename>javax.persistence.Tuple</interfacename> allowing
different types of access to the results, which we will expand on
next.</para>
</callout>
</calloutlist>
</example>
<section id="querycriteria-tuple-access">
<title>Accessing tuple elements</title>
<para>The <interfacename>javax.persistence.Tuple</interfacename>
contract provides 3 basic forms of access to the underlying
elements:</para>
<variablelist>
<varlistentry>
<term>typed</term>
<listitem>
<programlisting role="JAVA" language="JAVA">&lt;X&gt; X get(TupleElement&lt;X&gt; tupleElement)</programlisting>
<para>This allows typed access to the underlying tuple elements.
We see this in <xref linkend="ex-criteria-typedquery-tuple" /> in
the <emphasis>tuple.get( idPath )</emphasis> and
<emphasis>tuple.get( agePath )</emphasis> calls. Just about
everything is a
<interfacename>javax.persistence.TupleElement</interfacename>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>positional</term>
<listitem>
<programlisting role="JAVA" language="JAVA">Object get(int i)</programlisting>
<programlisting role="JAVA" language="JAVA">&lt;X&gt; X get(int i, Class&lt;X&gt; type)</programlisting>
<para>Very similar to what we saw in <xref
linkend="ex-criteria-typedquery-array" /> and <xref
linkend="ex-criteria-typedquery-array2" /> in terms of positional
access. Only the second form here provides typing, because the
user explicitly provides the typing on access. We see this in
<xref linkend="ex-criteria-typedquery-tuple" /> in the
<emphasis>tuple.get( 0 )</emphasis> and <emphasis>tuple.get( 1
)</emphasis> calls.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>aliased</term>
<listitem>
<programlisting role="JAVA" language="JAVA">Object get(String alias)</programlisting>
<programlisting role="JAVA" language="JAVA">&lt;X&gt; X get(String alias, Class&lt;X&gt; type)</programlisting>
<para>Again, only the second form here provides typing, because
the user explicitly provides the typing on access. We have not
seen an example of using this, but its trivial. We would simply,
for example, have applies an alias to either of the paths like
<emphasis>idPath.alias( "id" )</emphasis> and/or
<emphasis>agePath.alias( "age" )</emphasis> and we could have
accessed the individual tuple elements by those specified
aliases.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>
<section id="querycriteria-from">
<title>FROM clause</title>
<blockquote>
<attribution><citation><xref linkend="JPA2" />, section 6.5.2 Query
Roots, pg 262</citation></attribution>
<para>A CriteriaQuery object defines a query over one or more entity,
embeddable, or basic abstract schema types. The root objects of the
query are entities, from which the other types are reached by
navigation.</para>
</blockquote>
<note>
<para>All the individual parts of the FROM clause (roots, joins, paths)
implement the
<interfacename>javax.persistence.criteria.From</interfacename>
interface.</para>
</note>
<section id="querycriteria-from-root">
<title>Roots</title>
<para>Roots define the basis from which all joins, paths and attributes
are available in the query. In a criteria query, a root is always an
entity. Roots are defined and added to the criteria by the overloaded
<methodname>from</methodname> methods on
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>:</para>
<programlisting role="JAVA" language="JAVA">&lt;X&gt; Root&lt;X&gt; from(Class&lt;X&gt;)</programlisting>
<programlisting role="JAVA" language="JAVA">&lt;X&gt; Root&lt;X&gt; from(EntityType&lt;X&gt;)</programlisting>
<example>
<title>Adding a root</title>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;Person&gt; personCriteria = builder.createQuery( Person.class );
// create and add the root
person.from( Person.class );
...</programlisting>
</example>
<para>Criteria queries may define multiple roots, the effect of which is
to create a <ulink
url="http://en.wikipedia.org/wiki/Cartesian_product">cartesian
product</ulink> between the newly added root and the others. Here is an
example matching all single men and all single women:</para>
<programlisting role="JAVA" language="JAVA">CriteriaQuery query = builder.createQuery();
Root&lt;Person&gt; men = query.from( Person.class );
Root&lt;Person&gt; women = query.from( Person.class );
Predicate menRestriction = builder.and(
builder.equal( men.get( Person_.gender ), Gender.MALE ),
builder.equal( men.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
);
Predicate womenRestriction = builder.and(
builder.equal( women.get( Person_.gender ), Gender.FEMALE ),
builder.equal( women.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
);
query.where( builder.and( menRestriction, womenRestriction ) );</programlisting>
</section>
<section id="querycriteria-from-join">
<title>Joins</title>
<para>Joins allow navigation from other
<interfacename>javax.persistence.criteria.From</interfacename> to either
association or embedded attributes. Joins are created by the numerous
overloaded <methodname>join</methodname> methods of the
<interfacename>javax.persistence.criteria.From</interfacename>
interface:</para>
<example id="criteria-join-singular">
<title>Example with Embedded and ManyToOne</title>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;Person&gt; personCriteria = builder.createQuery( Person.class );
Root&lt;Person&gt; personRoot = person.from( Person.class );
// Person.address is an embedded attribute
Join&lt;Person,Address&gt; personAddress = personRoot.join( Person_.address );
// Address.country is a ManyToOne
Join&lt;Address,Country&gt; addressCountry = personAddress.join( Address_.country );
...</programlisting>
</example>
<example id="criteria-join-plural">
<title>Example with Collections</title>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;Person&gt; personCriteria = builder.createQuery( Person.class );
Root&lt;Person&gt; personRoot = person.from( Person.class );
Join&lt;Person,Order&gt; orders = personRoot.join( Person_.orders );
Join&lt;Order,LineItem&gt; orderLines = orders.join( Order_.lineItems );
...</programlisting>
</example>
</section>
<section id="querycriteria-from-fetch">
<title>Fetches</title>
<para>Just like in HQL and EJB-QL, we can specify that associated data
be fetched along with the owner. Fetches are created by the numerous
overloaded <methodname>fetch</methodname> methods of the
<interfacename>javax.persistence.criteria.From</interfacename>
interface:</para>
<example id="criteria-fetch-singular">
<title>Example with Embedded and ManyToOne</title>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;Person&gt; personCriteria = builder.createQuery( Person.class );
Root&lt;Person&gt; personRoot = person.from( Person.class );
// Person.address is an embedded attribute
Join&lt;Person,Address&gt; personAddress = personRoot.fetch( Person_.address );
// Address.country is a ManyToOne
Join&lt;Address,Country&gt; addressCountry = personAddress.fetch( Address_.country );
...</programlisting>
</example>
<note>
<para>Technically speaking, embedded attributes are always fetched
with their owner. However in order to define the fetching of
<emphasis>Address#country</emphasis> we needed a
<interfacename>javax.persistence.criteria.Fetch</interfacename> for
its parent path.</para>
</note>
<example id="criteria-fetch-plural">
<title>Example with Collections</title>
<programlisting role="JAVA" language="JAVA">CriteriaQuery&lt;Person&gt; personCriteria = builder.createQuery( Person.class );
Root&lt;Person&gt; personRoot = person.from( Person.class );
Join&lt;Person,Order&gt; orders = personRoot.fetch( Person_.orders );
Join&lt;Order,LineItem&gt; orderLines = orders.fetch( Order_.lineItems );
...</programlisting>
</example>
</section>
</section>
<section id="querycriteria-path">
<title>Path expressions</title>
<note>
<para>Roots, joins and fetches are themselves paths as well.</para>
</note>
</section>
<section id="querycriteria-param">
<title>Using parameters</title>
<example id="ex-querycriteria-param">
<title>Using parameters</title>
<programlistingco>
<areaspec>
<area coords="4" id="ex.criteria.param.1" />
<area coords="5" id="ex.criteria.param.2" />
<area coords="7" id="ex.criteria.param.3" />
</areaspec>
<programlisting>CriteriaQuery&lt;Person&gt; criteria = build.createQuery( Person.class );
Root&lt;Person&gt; personRoot = criteria.from( Person.class );
criteria.select( personRoot );
ParameterExpression&lt;String&gt; eyeColorParam = builder.parameter( String.class );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), eyeColorParam ) );
TypedQuery&lt;Person&gt; query = em.createQuery( criteria );
query.setParameter( eyeColorParam, "brown" );
List&lt;Person&gt; people = query.getResultList();</programlisting>
<calloutlist>
<callout arearefs="ex.criteria.param.1">
<para>Use the <methodname>parameter</methodname> method of
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
to obtain a parameter reference.</para>
</callout>
<callout arearefs="ex.criteria.param.2">
<para>Use the parameter reference in the criteria query.</para>
</callout>
<callout arearefs="ex.criteria.param.3">
<para>Use the parameter reference to bind the parameter value to
the
<interfacename>javax.persistence.TypedQuery</interfacename></para>
</callout>
</calloutlist>
</programlistingco>
</example>
</section>
</chapter>

View File

@ -1,919 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Inc or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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">
<chapter id="queryhql">
<title>JP-QL: The Object Query Language</title>
<para>The Java Persistence Query Language (JP-QL) has been heavily inspired
by HQL, the native Hibernate Query Language. Both are therefore very close
to SQL, but portable and independent of the database schema. People familiar
with HQL shouldn't have any problem using JP-QL. In fact HQL is a strict
superset of JP-QL and you use the same query API for both types of queries.
Portable JPA applications however should stick to JP-QL.</para>
<note>
<para>For a type-safe approach to query, we highly recommend you to use
the Criteria query, see <xref linkend="querycriteria" />.</para>
</note>
<sect1 id="queryhql-casesensitivity">
<title>Case Sensitivity</title>
<para>Queries are case-insensitive, except for names of Java classes and
properties. So <literal>SeLeCT</literal> is the same as
<literal>sELEct</literal> is the same as <literal>SELECT</literal> but
<literal>org.hibernate.eg.FOO</literal> is not
<literal>org.hibernate.eg.Foo</literal> and <literal>foo.barSet</literal>
is not <literal>foo.BARSET</literal>.</para>
<para>This manual uses lowercase JP-QL keywords. Some users find queries
with uppercase keywords more readable, but we find this convention ugly
when embedded in Java code.</para>
</sect1>
<sect1 id="queryhql-from">
<title>The from clause</title>
<para>The simplest possible JP-QL query is of the form:</para>
<programlisting>select c from eg.Cat c</programlisting>
<para>which simply returns all instances of the class
<literal>eg.Cat</literal>. Unlike HQL, the select clause is not optional
in JP-QL. We don't usually need to qualify the class name, since the
entity name defaults to the unqualified class name
(<literal>@Entity</literal>). So we almost always just write:</para>
<programlisting>select c from Cat c</programlisting>
<para>As you may have noticed you can assign aliases to classes, the
<literal>as</literal> keywork is optional. An alias allows you to refer to
<literal>Cat</literal> in other parts of the query.</para>
<programlisting>select cat from Cat as cat</programlisting>
<para>Multiple classes may appear, resulting in a cartesian product or
"cross" join.</para>
<programlisting>select formula, parameter from Formula as formula, Parameter as parameter</programlisting>
<para>It is considered good practice to name query aliases using an
initial lowercase, consistent with Java naming standards for local
variables (eg. <literal>domesticCat</literal>).</para>
</sect1>
<sect1 id="queryhql-joins" revision="1">
<title>Associations and joins</title>
<para>You may also assign aliases to associated entities, or even to
elements of a collection of values, using a
<literal>join</literal>.</para>
<programlisting>select cat, mate, kitten from Cat as cat
inner join cat.mate as mate
left outer join cat.kittens as kitten</programlisting>
<programlisting>select cat from Cat as cat left join cat.mate.kittens as kittens</programlisting>
<para>The supported join types are borrowed from ANSI SQL</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>inner join</literal></para>
</listitem>
<listitem>
<para><literal>left outer join</literal></para>
</listitem>
</itemizedlist>
<para>The <literal>inner join</literal>, <literal>left outer
join</literal> constructs may be abbreviated.</para>
<programlisting>select cat, mate, kitten from Cat as cat
join cat.mate as mate
left join cat.kittens as kitten</programlisting>
<para>In addition, a "fetch" join allows associations or collections of
values to be initialized along with their parent objects, using a single
select. This is particularly useful in the case of a collection. It
effectively overrides the fetching options in the associations and
collection mapping metadata. See the Performance chapter of the Hibernate
reference guide for more information.</para>
<programlisting>select cat from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens</programlisting>
<para>A fetch join does not usually need to assign an alias, because the
associated objects should not be used in the <literal>where</literal>
clause (or any other clause). Also, the associated objects are not
returned directly in the query results. Instead, they may be accessed via
the parent object. The only reason we might need an alias is if we are
recursively join fetching a further collection:</para>
<programlisting>select cat from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens child
left join fetch child.kittens</programlisting>
<para>Note that the <literal>fetch</literal> construct may not be used in
queries called using <literal>scroll()</literal> or
<literal>iterate()</literal>. Nor should <literal>fetch</literal> be used
together with <literal>setMaxResults()</literal> or
<literal>setFirstResult()</literal>. It is possible to create a cartesian
product by join fetching more than one collection in a query (as in the
example above), be careful the result of this product isn't bigger than
you expect. Join fetching multiple collection roles gives unexpected
results for bag mappings as it is impossible for Hibernate to
differentiate legit duplicates of a given bag from artificial duplicates
created by the multi-table cartesian product.</para>
<para>If you are using property-level lazy fetching (with bytecode
instrumentation), it is possible to force Hibernate to fetch the lazy
properties immediately (in the first query) using <literal>fetch all
properties</literal>. This is Hibernate specific option:</para>
<programlisting>select doc from Document doc fetch all properties order by doc.name</programlisting>
<programlisting>select doc from Document doc fetch all properties where lower(doc.name) like '%cats%'</programlisting>
</sect1>
<sect1 id="queryhql-select">
<title>The select clause</title>
<para>The <literal>select</literal> clause picks which objects and
properties to return in the query result set. Consider:</para>
<programlisting>select mate
from Cat as cat
inner join cat.mate as mate</programlisting>
<para>The query will select <literal>mate</literal>s of other
<literal>Cat</literal>s. Actually, you may express this query more
compactly as:</para>
<programlisting>select cat.mate from Cat cat</programlisting>
<para>Queries may return properties of any value type including properties
of component type:</para>
<programlisting>select cat.name from DomesticCat cat
where cat.name like 'fri%'</programlisting>
<programlisting>select cust.name.firstName from Customer as cust</programlisting>
<para>Queries may return multiple objects and/or properties as an array of
type <literal>Object[]</literal>,</para>
<programlisting>select mother, offspr, mate.name
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr</programlisting>
<para>or as a <literal>List</literal> (HQL specific feature)</para>
<programlisting>select new list(mother, offspr, mate.name)
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr</programlisting>
<para>or as an actual type-safe Java object (often called a view
object),</para>
<programlisting>select new Family(mother, mate, offspr)
from DomesticCat as mother
join mother.mate as mate
left join mother.kittens as offspr</programlisting>
<para>assuming that the class <literal>Family</literal> has an appropriate
constructor.</para>
<para>You may assign aliases to selected expressions using
<literal>as</literal>:</para>
<programlisting>select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
from Cat cat</programlisting>
<para>This is most useful when used together with <literal>select new
map</literal> (HQL specific feature):</para>
<programlisting>select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
from Cat cat</programlisting>
<para>This query returns a <literal>Map</literal> from aliases to selected
values.</para>
</sect1>
<sect1 id="queryhql-aggregation">
<title>Aggregate functions</title>
<para>HQL queries may even return the results of aggregate functions on
properties:</para>
<programlisting>select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
from Cat cat</programlisting>
<para>The supported aggregate functions are</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>avg(...), avg(distinct ...), sum(...), sum(distinct
...), min(...), max(...)</literal></para>
</listitem>
<listitem>
<para><literal>count(*)</literal></para>
</listitem>
<listitem>
<para><literal>count(...), count(distinct ...),
count(all...)</literal></para>
</listitem>
</itemizedlist>
<para>You may use arithmetic operators, concatenation, and recognized SQL
functions in the select clause (depending on configured dialect, HQL
specific feature):</para>
<programlisting>select cat.weight + sum(kitten.weight)
from Cat cat
join cat.kittens kitten
group by cat.id, cat.weight</programlisting>
<programlisting>select firstName||' '||initial||' '||upper(lastName) from Person</programlisting>
<para>The <literal>distinct</literal> and <literal>all</literal> keywords
may be used and have the same semantics as in SQL.</para>
<programlisting>select distinct cat.name from Cat cat
select count(distinct cat.name), count(cat) from Cat cat</programlisting>
</sect1>
<sect1 id="queryhql-polymorphism">
<title>Polymorphic queries</title>
<para>A query like:</para>
<programlisting>select cat from Cat as cat</programlisting>
<para>returns instances not only of <literal>Cat</literal>, but also of
subclasses like <literal>DomesticCat</literal>. Hibernate queries may name
<emphasis>any</emphasis> Java class or interface in the
<literal>from</literal> clause (portable JP-QL queries should only name
mapped entities). The query will return instances of all persistent
classes that extend that class or implement the interface. The following
query would return all persistent objects:</para>
<programlisting>from java.lang.Object o // HQL only</programlisting>
<para>The interface <literal>Named</literal> might be implemented by
various persistent classes:</para>
<programlisting>from Named n, Named m where n.name = m.name // HQL only</programlisting>
<para>Note that these last two queries will require more than one SQL
<literal>SELECT</literal>. This means that the <literal>order by</literal>
clause does not correctly order the whole result set. (It also means you
can't call these queries using <literal>Query.scroll()</literal>.)</para>
</sect1>
<sect1 id="queryhql-where">
<title>The where clause</title>
<para>The <literal>where</literal> clause allows you to narrow the list of
instances returned. If no alias exists, you may refer to properties by
name:</para>
<programlisting>select cat from Cat cat where cat.name='Fritz'</programlisting>
<para>returns instances of <literal>Cat</literal> named 'Fritz'.</para>
<programlisting>select foo
from Foo foo, Bar bar
where foo.startDate = bar.date</programlisting>
<para>will return all instances of <literal>Foo</literal> for which there
exists an instance of <literal>bar</literal> with a
<literal>date</literal> property equal to the <literal>startDate</literal>
property of the <literal>Foo</literal>. Compound path expressions make the
<literal>where</literal> clause extremely powerful. Consider:</para>
<programlisting>select cat from Cat cat where cat.mate.name is not null</programlisting>
<para>This query translates to an SQL query with a table (inner) join. If
you were to write something like</para>
<programlisting>select foo from Foo foo
where foo.bar.baz.customer.address.city is not null</programlisting>
<para>you would end up with a query that would require four table joins in
SQL.</para>
<para>The <literal>=</literal> operator may be used to compare not only
properties, but also instances:</para>
<programlisting>select cat, rival from Cat cat, Cat rival where cat.mate = rival.mate</programlisting>
<programlisting>select cat, mate
from Cat cat, Cat mate
where cat.mate = mate</programlisting>
<para>The special property (lowercase) <literal>id</literal> may be used
to reference the unique identifier of an object. (You may also use its
mapped identifer property name.). Note that this keyword is specific to
HQL.</para>
<programlisting>select cat from Cat as cat where cat.id = 123
select cat from Cat as cat where cat.mate.id = 69</programlisting>
<para>The second query is efficient. No table join is required!</para>
<para>Properties of composite identifiers may also be used. Suppose
<literal>Person</literal> has a composite identifier consisting of
<literal>country</literal> and <literal>medicareNumber</literal>.</para>
<programlisting>select person from bank.Person person
where person.id.country = 'AU'
and person.id.medicareNumber = 123456</programlisting>
<programlisting>select account from bank.Account account
where account.owner.id.country = 'AU'
and account.owner.id.medicareNumber = 123456</programlisting>
<para>Once again, the second query requires no table join.</para>
<para>Likewise, the special property <literal>class</literal> accesses the
discriminator value of an instance in the case of polymorphic persistence.
A Java class name embedded in the where clause will be translated to its
discriminator value. Once again, this is specific to HQL.</para>
<programlisting>select cat from Cat cat where cat.class = DomesticCat</programlisting>
<para>You may also specify properties of components or composite user
types (and of components of components, etc). Never try to use a
path-expression that ends in a property of component type (as opposed to a
property of a component). For example, if <literal>store.owner</literal>
is an entity with a component <literal>address</literal></para>
<programlisting>store.owner.address.city // okay
store.owner.address // error!</programlisting>
<para>An "any" type has the special properties <literal>id</literal> and
<literal>class</literal>, allowing us to express a join in the following
way (where <literal>AuditLog.item</literal> is a property mapped with
<literal>&lt;any&gt;</literal>). <literal>Any</literal> is specific to
Hibernate</para>
<programlisting>from AuditLog log, Payment payment
where log.item.class = 'Payment' and log.item.id = payment.id</programlisting>
<para>Notice that <literal>log.item.class</literal> and
<literal>payment.class</literal> would refer to the values of completely
different database columns in the above query.</para>
</sect1>
<sect1 id="queryhql-expressions">
<title>Expressions</title>
<para>Expressions allowed in the <literal>where</literal> clause include
most of the kind of things you could write in SQL:</para>
<itemizedlist spacing="compact">
<listitem>
<para>mathematical operators <literal>+, -, *, /</literal></para>
</listitem>
<listitem>
<para>binary comparison operators <literal>=, &gt;=, &lt;=, &lt;&gt;,
!=, like</literal></para>
</listitem>
<listitem>
<para>logical operations <literal>and, or, not</literal></para>
</listitem>
<listitem>
<para>Parentheses <literal>( )</literal>, indicating grouping</para>
</listitem>
<listitem>
<para><literal>in</literal>, <literal>not in</literal>,
<literal>between</literal>, <literal>is null</literal>, <literal>is
not null</literal>, <literal>is empty</literal>, <literal>is not
empty</literal>, <literal>member of</literal> and <literal>not member
of</literal></para>
</listitem>
<listitem>
<para><literal>exists</literal>, <literal>all</literal>,
<literal>any</literal>, <literal>some</literal> (taking
subqueries)</para>
</listitem>
<listitem>
<para>"Simple" case, <literal>case ... when ... then ... else ...
end</literal>, and "searched" case, <literal>case when ... then ...
else ... end</literal></para>
</listitem>
<listitem>
<para>string concatenation <literal>...||...</literal> or
<literal>concat(...,...) (use concat() for portable JP-QL
queries)</literal></para>
</listitem>
<listitem>
<para><literal>current_date()</literal>,
<literal>current_time()</literal>,
<literal>current_timestamp()</literal></para>
</listitem>
<listitem>
<para><literal>second(...)</literal>, <literal>minute(...)</literal>,
<literal>hour(...)</literal>, <literal>day(...)</literal>,
<literal>month(...)</literal>, <literal>year(...)</literal>, (specific
to HQL)</para>
</listitem>
<listitem>
<para>Any function or operator: <literal>substring(), trim(), lower(),
upper(), length(), locate(), abs(), sqrt(),
bit_length()</literal></para>
</listitem>
<listitem>
<para><literal>coalesce()</literal> and
<literal>nullif()</literal></para>
</listitem>
<listitem>
<para><literal>TYPE ... in ...</literal>, where the first argument is
an identifier variable and the second argument is the subclass to
restrict polymorphism to (or a list of subclasses surrounded by
parenthesis)</para>
</listitem>
<listitem>
<para><literal>cast(... as ...)</literal>, where the second argument
is the name of a Hibernate type, and <literal>extract(... from
...)</literal> if ANSI <literal>cast()</literal> and
<literal>extract()</literal> is supported by the underlying
database</para>
</listitem>
<listitem>
<para>Any database-supported SQL scalar function like
<literal>sign()</literal>, <literal>trunc()</literal>,
<literal>rtrim()</literal>, <literal>sin()</literal></para>
</listitem>
<listitem>
<para>JDBC IN parameters <literal>?</literal></para>
</listitem>
<listitem>
<para>named parameters <literal>:name</literal>,
<literal>:start_date</literal>, <literal>:x1</literal></para>
</listitem>
<listitem>
<para>SQL literals <literal>'foo'</literal>, <literal>69</literal>,
<literal>'1970-01-01 10:00:01.0'</literal></para>
</listitem>
<listitem>
<para>JDBC escape syntax for dates (dependent on your JDBC driver
support) (eg. <code>where date = {d '2008-12-31'}</code>)</para>
</listitem>
<listitem>
<para>Java <literal>public static final</literal> constants
<literal>eg.Color.TABBY</literal></para>
</listitem>
</itemizedlist>
<para><literal>in</literal> and <literal>between</literal> may be used as
follows:</para>
<programlisting>select cat from DomesticCat cat where cat.name between 'A' and 'B'</programlisting>
<programlisting>select cat from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )</programlisting>
<para>and the negated forms may be written</para>
<programlisting>select cat from DomesticCat cat where cat.name not between 'A' and 'B'</programlisting>
<programlisting>select cat from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )</programlisting>
<para>Likewise, <literal>is null</literal> and <literal>is not
null</literal> may be used to test for null values.</para>
<para>Booleans may be easily used in expressions by declaring HQL query
substitutions in Hibernate configuration:</para>
<programlisting>hibernate.query.substitutions true 1, false 0</programlisting>
<para>This will replace the keywords <literal>true</literal> and
<literal>false</literal> with the literals <literal>1</literal> and
<literal>0</literal> in the translated SQL from this HQL:</para>
<programlisting>select cat from Cat cat where cat.alive = true</programlisting>
<para>You may test the size of a collection with the special property
<literal>size</literal>, or the special <literal>size()</literal> function
(HQL specific feature).</para>
<programlisting>select cat from Cat cat where cat.kittens.size &gt; 0</programlisting>
<programlisting>select cat from Cat cat where size(cat.kittens) &gt; 0</programlisting>
<para>For indexed collections, you may refer to the minimum and maximum
indices using <literal>minindex</literal> and <literal>maxindex</literal>
functions. Similarly, you may refer to the minimum and maximum elements of
a collection of basic type using the <literal>minelement</literal> and
<literal>maxelement</literal> functions. These are HQL specific
features.</para>
<programlisting>select cal from Calendar cal where maxelement(cal.holidays) &gt; current date</programlisting>
<programlisting>select order from Order order where maxindex(order.items) &gt; 100</programlisting>
<programlisting>select order from Order order where minelement(order.items) &gt; 10000</programlisting>
<para>The SQL functions <literal>any, some, all, exists, in</literal> are
supported when passed the element or index set of a collection
(<literal>elements</literal> and <literal>indices</literal> functions) or
the result of a subquery (see below). While subqueries are supported by
JP-QL, <literal>elements</literal> and <literal>indices</literal> are
specific HQL features.</para>
<programlisting>select mother from Cat as mother, Cat as kit
where kit in elements(foo.kittens)</programlisting>
<programlisting>select p from NameList list, Person p
where p.name = some elements(list.names)</programlisting>
<programlisting>select cat from Cat cat where exists elements(cat.kittens)</programlisting>
<programlisting>select cat from Player p where 3 &gt; all elements(p.scores)</programlisting>
<programlisting>select cat from Show show where 'fizard' in indices(show.acts)</programlisting>
<para>Note that these constructs - <literal>size</literal>,
<literal>elements</literal>, <literal>indices</literal>,
<literal>minindex</literal>, <literal>maxindex</literal>,
<literal>minelement</literal>, <literal>maxelement</literal> - may only be
used in the where clause in Hibernate.</para>
<para>JP-QL lets you access the key or the value of a map by using the
<literal>KEY()</literal> and <literal>VALUE()</literal> operations (even
access the Entry object using <literal>ENTRY()</literal>)</para>
<programlisting>SELECT i.name, VALUE(p) FROM Item i JOIN i.photos p WHERE KEY(p) LIKE %egret</programlisting>
<para>In HQL, elements of indexed collections (arrays, lists, maps) may be
referred to by index (in a where clause only):</para>
<programlisting>select order from Order order where order.items[0].id = 1234</programlisting>
<programlisting>select person from Person person, Calendar calendar
where calendar.holidays['national day'] = person.birthDay
and person.nationality.calendar = calendar</programlisting>
<programlisting>select item from Item item, Order order
where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11</programlisting>
<programlisting>select item from Item item, Order order
where order.items[ maxindex(order.items) ] = item and order.id = 11</programlisting>
<para>The expression inside <literal>[]</literal> may even be an
arithmetic expression.</para>
<programlisting>select item from Item item, Order order
where order.items[ size(order.items) - 1 ] = item</programlisting>
<para>HQL also provides the built-in <literal>index()</literal> function,
for elements of a one-to-many association or collection of values.</para>
<programlisting>select item, index(item) from Order order
join order.items item
where index(item) &lt; 5</programlisting>
<para>Scalar SQL functions supported by the underlying database may be
used</para>
<programlisting>select cat from DomesticCat cat where upper(cat.name) like 'FRI%'</programlisting>
<para>If you are not yet convinced by all this, think how much longer and
less readable the following query would be in SQL:</para>
<programlisting>select cust
from Product prod,
Store store
inner join store.customers cust
where prod.name = 'widget'
and store.location.name in ( 'Melbourne', 'Sydney' )
and prod = all elements(cust.currentOrder.lineItems)</programlisting>
<para><emphasis>Hint:</emphasis> something like</para>
<programlisting>SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
FROM customers cust,
stores store,
locations loc,
store_customers sc,
product prod
WHERE prod.name = 'widget'
AND store.loc_id = loc.id
AND loc.name IN ( 'Melbourne', 'Sydney' )
AND sc.store_id = store.id
AND sc.cust_id = cust.id
AND prod.id = ALL(
SELECT item.prod_id
FROM line_items item, orders o
WHERE item.order_id = o.id
AND cust.current_order = o.id
)</programlisting>
</sect1>
<sect1 id="queryhql-ordering">
<title>The order by clause</title>
<para>The list returned by a query may be ordered by any property of a
returned class or components:</para>
<programlisting>select cat from DomesticCat cat
order by cat.name asc, cat.weight desc, cat.birthdate</programlisting>
<para>The optional <literal>asc</literal> or <literal>desc</literal>
indicate ascending or descending order respectively.</para>
</sect1>
<sect1 id="queryhql-grouping">
<title>The group by clause</title>
<para>A query that returns aggregate values may be grouped by any property
of a returned class or components:</para>
<programlisting>select cat.color, sum(cat.weight), count(cat)
from Cat cat
group by cat.color</programlisting>
<programlisting>select foo.id, avg(name), max(name)
from Foo foo join foo.names name
group by foo.id</programlisting>
<para>A <literal>having</literal> clause is also allowed.</para>
<programlisting>select cat.color, sum(cat.weight), count(cat)
from Cat cat
group by cat.color
having cat.color in (eg.Color.TABBY, eg.Color.BLACK)</programlisting>
<para>SQL functions and aggregate functions are allowed in the
<literal>having</literal> and <literal>order by</literal> clauses, if
supported by the underlying database (eg. not in MySQL).</para>
<programlisting>select cat
from Cat cat
join cat.kittens kitten
group by cat
having avg(kitten.weight) &gt; 100
order by count(kitten) asc, sum(kitten.weight) desc</programlisting>
<para>Note that neither the <literal>group by</literal> clause nor the
<literal>order by</literal> clause may contain arithmetic
expressions.</para>
</sect1>
<sect1 id="queryhql-subqueries">
<title>Subqueries</title>
<para>For databases that support subselects, JP-QL supports subqueries
within queries. A subquery must be surrounded by parentheses (often by an
SQL aggregate function call). Even correlated subqueries (subqueries that
refer to an alias in the outer query) are allowed.</para>
<programlisting>select fatcat from Cat as fatcat
where fatcat.weight &gt; (
select avg(cat.weight) from DomesticCat cat
)</programlisting>
<programlisting>select cat from DomesticCat as cat
where cat.name = some (
select name.nickName from Name as name
)</programlisting>
<programlisting>select cat from Cat as cat
where not exists (
from Cat as mate where mate.mate = cat
)</programlisting>
<programlisting>select cat from DomesticCat as cat
where cat.name not in (
select name.nickName from Name as name
)</programlisting>
<para>For subqueries with more than one expression in the select list, you
can use a tuple constructor:</para>
<programlisting>select cat from Cat as cat
where not ( cat.name, cat.color ) in (
select cat.name, cat.color from DomesticCat cat
)</programlisting>
<para>Note that on some databases (but not Oracle or HSQLDB), you can use
tuple constructors in other contexts, for example when querying components
or composite user types:</para>
<programlisting>select cat from Person where name = ('Gavin', 'A', 'King')</programlisting>
<para>Which is equivalent to the more verbose:</para>
<programlisting>select cat from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')</programlisting>
<para>There are two good reasons you might not want to do this kind of
thing: first, it is not completely portable between database platforms;
second, the query is now dependent upon the ordering of properties in the
mapping document.</para>
</sect1>
<sect1 id="queryhql-examples">
<title>JP-QL examples</title>
<para>Hibernate queries can be quite powerful and complex. In fact, the
power of the query language is one of Hibernate's main selling points (and
now JP-QL). Here are some example queries very similar to queries that I
used on a recent project. Note that most queries you will write are much
simpler than these!</para>
<para>The following query returns the order id, number of items and total
value of the order for all unpaid orders for a particular customer and
given minimum total value, ordering the results by total value. In
determining the prices, it uses the current catalog. The resulting SQL
query, against the <literal>ORDER</literal>,
<literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
<literal>CATALOG</literal> and <literal>PRICE</literal> tables has four
inner joins and an (uncorrelated) subselect.</para>
<programlisting>select order.id, sum(price.amount), count(item)
from Order as order
join order.lineItems as item
join item.product as product,
Catalog as catalog
join catalog.prices as price
where order.paid = false
and order.customer = :customer
and price.product = product
and catalog.effectiveDate &lt; sysdate
and catalog.effectiveDate &gt;= all (
select cat.effectiveDate
from Catalog as cat
where cat.effectiveDate &lt; sysdate
)
group by order
having sum(price.amount) &gt; :minAmount
order by sum(price.amount) desc</programlisting>
<para>What a monster! Actually, in real life, I'm not very keen on
subqueries, so my query was really more like this:</para>
<programlisting>select order.id, sum(price.amount), count(item)
from Order as order
join order.lineItems as item
join item.product as product,
Catalog as catalog
join catalog.prices as price
where order.paid = false
and order.customer = :customer
and price.product = product
and catalog = :currentCatalog
group by order
having sum(price.amount) &gt; :minAmount
order by sum(price.amount) desc</programlisting>
<para>The next query counts the number of payments in each status,
excluding all payments in the <literal>AWAITING_APPROVAL</literal> status
where the most recent status change was made by the current user. It
translates to an SQL query with two inner joins and a correlated subselect
against the <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>
and <literal>PAYMENT_STATUS_CHANGE</literal> tables.</para>
<programlisting>select count(payment), status.name
from Payment as payment
join payment.currentStatus as status
join payment.statusChanges as statusChange
where payment.status.name &lt;&gt; PaymentStatus.AWAITING_APPROVAL
or (
statusChange.timeStamp = (
select max(change.timeStamp)
from PaymentStatusChange change
where change.payment = payment
)
and statusChange.user &lt;&gt; :currentUser
)
group by status.name, status.sortOrder
order by status.sortOrder</programlisting>
<para>If I would have mapped the <literal>statusChanges</literal>
collection as a list, instead of a set, the query would have been much
simpler to write.</para>
<programlisting>select count(payment), status.name
from Payment as payment
join payment.currentStatus as status
where payment.status.name &lt;&gt; PaymentStatus.AWAITING_APPROVAL
or payment.statusChanges[ maxIndex(payment.statusChanges) ].user &lt;&gt; :currentUser
group by status.name, status.sortOrder
order by status.sortOrder</programlisting>
<para>However the query would have been HQL specific.</para>
<para>The next query uses the MS SQL Server <literal>isNull()</literal>
function to return all the accounts and unpaid payments for the
organization to which the current user belongs. It translates to an SQL
query with three inner joins, an outer join and a subselect against the
<literal>ACCOUNT</literal>, <literal>PAYMENT</literal>,
<literal>PAYMENT_STATUS</literal>, <literal>ACCOUNT_TYPE</literal>,
<literal>ORGANIZATION</literal> and <literal>ORG_USER</literal>
tables.</para>
<programlisting>select account, payment
from Account as account
join account.holder.users as user
left outer join account.payments as payment
where :currentUser = user
and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
order by account.type.sortOrder, account.accountNumber, payment.dueDate</programlisting>
</sect1>
<sect1 id="queryhql-bulk">
<title>Bulk UPDATE &amp; DELETE Statements</title>
<para>Hibernate now supports UPDATE and DELETE statements in HQL/JP-QL.
See <xref linkend="batch-direct" /> for details.</para>
</sect1>
<sect1 id="queryhql-tipstricks">
<title>Tips &amp; Tricks</title>
<para>To order a result by the size of a collection, use the following
query:</para>
<programlisting>select usr.id, usr.name
from User as usr
left join usr.messages as msg
group by usr.id, usr.name
order by count(msg)</programlisting>
<para>If your database supports subselects, you can place a condition upon
selection size in the where clause of your query:</para>
<programlisting>from User usr where size(usr.messages) &gt;= 1</programlisting>
<para>If your database doesn't support subselects, use the following
query:</para>
<programlisting>select usr.id, usr.name
from User usr.name
join usr.messages msg
group by usr.id, usr.name
having count(msg) &gt;= 1</programlisting>
<para>As this solution can't return a <literal>User</literal> with zero
messages because of the inner join, the following form is also
useful:</para>
<programlisting>select usr.id, usr.name
from User as usr
left join usr.messages as msg
group by usr.id, usr.name
having count(msg) = 0</programlisting>
</sect1>
</chapter>

View File

@ -1,951 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Inc or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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">
<chapter id="transactions" revision="1">
<title>Transactions and Concurrency</title>
<para>The most important point about Hibernate Entity Manager and
concurrency control is that it is very easy to understand. Hibernate Entity
Manager directly uses JDBC connections and JTA resources without adding any
additional locking behavior. We highly recommend you spend some time with
the JDBC, ANSI, and transaction isolation specification of your database
management system. Hibernate Entity Manager only adds automatic versioning
but does not lock objects in memory or change the isolation level of your
database transactions. Basically, use Hibernate Entity Manager like you
would use direct JDBC (or JTA/CMT) with your database resources.</para>
<para>We start the discussion of concurrency control in Hibernate with the
granularity of <literal>EntityManagerFactory</literal>, and
<literal>EntityManager</literal>, as well as database transactions and long
units of work..</para>
<para>In this chapter, and unless explicitly expressed, we will mix and
match the concept of entity manager and persistence context. One is an API
and programming object, the other a definition of scope. However, keep in
mind the essential difference. A persistence context is usually bound to a
JTA transaction in Java EE, and a persistence context starts and ends at
transaction boundaries (transaction-scoped) unless you use an extended
entity manager. Please refer to <xref
linkend="architecture-ejb-persistctxscope" /> for more information.</para>
<sect1 id="transactions-basics">
<title>Entity manager and transaction scopes</title>
<para>A <literal>EntityManagerFactory</literal> is an expensive-to-create,
threadsafe object intended to be shared by all application threads. It is
created once, usually on application startup.</para>
<para>An <literal>EntityManager</literal> is an inexpensive,
non-threadsafe object that should be used once, for a single business
process, a single unit of work, and then discarded. An
<literal>EntityManager</literal> will not obtain a JDBC
<literal>Connection</literal> (or a <literal>Datasource</literal>) unless
it is needed, so you may safely open and close an
<literal>EntityManager</literal> even if you are not sure that data access
will be needed to serve a particular request. (This becomes important as
soon as you are implementing some of the following patterns using request
interception.)</para>
<para>To complete this picture you also have to think about database
transactions. A database transaction has to be as short as possible, to
reduce lock contention in the database. Long database transactions will
prevent your application from scaling to highly concurrent load.</para>
<para>What is the scope of a unit of work? Can a single Hibernate
<literal>EntityManager</literal> span several database transactions or is
this a one-to-one relationship of scopes? When should you open and close a
<literal>Session</literal> and how do you demarcate the database
transaction boundaries?</para>
<sect2 id="transactions-basics-uow">
<title>Unit of work</title>
<para>First, don't use the
<emphasis>entitymanager-per-operation</emphasis> antipattern, that is,
don't open and close an <literal>EntityManager</literal> for every
simple database call in a single thread! Of course, the same is true for
database transactions. Database calls in an application are made using a
planned sequence, they are grouped into atomic units of work. (Note that
this also means that auto-commit after every single SQL statement is
useless in an application, this mode is intended for ad-hoc SQL console
work.)</para>
<para>The most common pattern in a multi-user client/server application
is <emphasis>entitymanager-per-request</emphasis>. In this model, a
request from the client is send to the server (where the JPA persistence
layer runs), a new <literal>EntityManager</literal> is opened, and all
database operations are executed in this unit of work. Once the work has
been completed (and the response for the client has been prepared), the
persistence context is flushed and closed, as well as the entity manager
object. You would also use a single database transaction to serve the
clients request. The relationship between the two is one-to-one and this
model is a perfect fit for many applications.</para>
<para>This is the default JPA persistence model in a Java EE environment
(JTA bounded, transaction-scoped persistence context); injected (or
looked up) entity managers share the same persistence context for a
particular JTA transaction. The beauty of JPA is that you don't have to
care about that anymore and just see data access through entity manager
and demarcation of transaction scope on session beans as completely
orthogonal.</para>
<para>The challenge is the implementation of this (and other) behavior
outside an EJB3 container: not only has the
<literal>EntityManager</literal> and resource-local transaction to be
started and ended correctly, but they also have to be accessible for
data access operations. The demarcation of a unit of work is ideally
implemented using an interceptor that runs when a request hits the
non-EJB3 container server and before the response will be send (i.e. a
<literal>ServletFilter</literal> if you are using a standalone servlet
container). We recommend to bind the <literal>EntityManager</literal> to
the thread that serves the request, using a
<literal>ThreadLocal</literal> variable. This allows easy access (like
accessing a static variable) in all code that runs in this thread.
Depending on the database transaction demarcation mechanism you chose,
you might also keep the transaction context in a
<literal>ThreadLocal</literal> variable. The implementation patterns for
this are known as <emphasis>ThreadLocal Session</emphasis> and
<emphasis>Open Session in View</emphasis> in the Hibernate community.
You can easily extend the <literal>HibernateUtil</literal> shown in the
Hibernate reference documentation to implement this pattern, you don't
need any external software (it's in fact very trivial). Of course, you'd
have to find a way to implement an interceptor and set it up in your
environment. See the Hibernate website for tips and examples. Once
again, remember that your first choice is naturally an EJB3 container -
preferably a light and modular one such as JBoss application
server.</para>
</sect2>
<sect2 id="transactions-basics-apptx">
<title>Long units of work</title>
<para>The entitymanager-per-request pattern is not the only useful
concept you can use to design units of work. Many business processes
require a whole series of interactions with the user interleaved with
database accesses. In web and enterprise applications it is not
acceptable for a database transaction to span a user interaction with
possibly long waiting time between requests. Consider the following
example:</para>
<itemizedlist>
<listitem>
<para>The first screen of a dialog opens, the data seen by the user
has been loaded in a particular <literal>EntityManager</literal> and
resource-local transaction. The user is free to modify the detached
objects.</para>
</listitem>
<listitem>
<para>The user clicks "Save" after 5 minutes and expects his
modifications to be made persistent; he also expects that he was the
only person editing this information and that no conflicting
modification can occur.</para>
</listitem>
</itemizedlist>
<para>We call this unit of work, from the point of view of the user, a
long running <emphasis>application transaction</emphasis>. There are
many ways how you can implement this in your application.</para>
<para>A first naive implementation might keep the
<literal>EntityManager</literal> and database transaction open during
user think time, with locks held in the database to prevent concurrent
modification, and to guarantee isolation and atomicity. This is of
course an anti-pattern, a pessimistic approach, since lock contention
would not allow the application to scale with the number of concurrent
users.</para>
<para>Clearly, we have to use several database transactions to implement
the application transaction. In this case, maintaining isolation of
business processes becomes the partial responsibility of the application
tier. A single application transaction usually spans several database
transactions. It will be atomic if only one of these database
transactions (the last one) stores the updated data, all others simply
read data (e.g. in a wizard-style dialog spanning several
request/response cycles). This is easier to implement than it might
sound, especially if you use JPA entity manager and persistence context
features:</para>
<itemizedlist>
<listitem>
<para><emphasis>Automatic Versioning</emphasis> - An entity manager
can do automatic optimistic concurrency control for you, it can
automatically detect if a concurrent modification occurred during
user think time (usually by comparing version numbers or timestamps
when updating the data in the final resource-local
transaction).</para>
</listitem>
<listitem>
<para><emphasis>Detached Entities</emphasis> - If you decide to use
the already discussed <emphasis>entity-per-request</emphasis>
pattern, all loaded instances will be in detached state during user
think time. The entity manager allows you to merge the detached
(modified) state and persist the modifications, the pattern is
called
<emphasis>entitymanager-per-request-with-detached-entities</emphasis>.
Automatic versioning is used to isolate concurrent
modifications.</para>
</listitem>
<listitem>
<para><emphasis>Extended Entity Manager</emphasis> - The Hibernate
Entity Manager may be disconnected from the underlying JDBC
connection between two client calls and reconnected when a new
client request occurs. This pattern is known as
<emphasis>entitymanager-per-application-transaction</emphasis> and
makes even merging unnecessary. An extend persistence context is
responsible to collect and retain any modification (persist, merge,
remove) made outside a transaction. The next client call made inside
an active transaction (typically the last operation of a user
conversation) will execute all queued modifications. Automatic
versioning is used to isolate concurrent modifications.</para>
</listitem>
</itemizedlist>
<para>Both
<emphasis>entitymanager-per-request-with-detached-objects</emphasis> and
<emphasis>entitymanager-per-application-transaction</emphasis> have
advantages and disadvantages, we discuss them later in this chapter in
the context of optimistic concurrency control.</para>
<para>TODO: This note should probably come later.</para>
</sect2>
<sect2 id="transactions-basics-identity">
<title>Considering object identity</title>
<para>An application may concurrently access the same persistent state
in two different persistence contexts. However, an instance of a managed
class is never shared between two persistence contexts. Hence there are
two different notions of identity:</para>
<variablelist spacing="compact">
<varlistentry>
<term>Database Identity</term>
<listitem>
<para><literal>foo.getId().equals( bar.getId() )</literal></para>
</listitem>
</varlistentry>
<varlistentry>
<term>JVM Identity</term>
<listitem>
<para><literal>foo==bar</literal></para>
</listitem>
</varlistentry>
</variablelist>
<para>Then for objects attached to a <emphasis>particular</emphasis>
persistence context (i.e. in the scope of an
<literal>EntityManager</literal>) the two notions are equivalent, and
JVM identity for database identity is guaranteed by the Hibernate Entity
Manager. However, while the application might concurrently access the
"same" (persistent identity) business object in two different
persistence contexts, the two instances will actually be "different"
(JVM identity). Conflicts are resolved using (automatic versioning) at
flush/commit time, using an optimistic approach.</para>
<para>This approach leaves Hibernate and the database to worry about
concurrency; it also provides the best scalability, since guaranteeing
identity in single-threaded units of work only doesn't need expensive
locking or other means of synchronization. The application never needs
to synchronize on any business object, as long as it sticks to a single
thread per <literal>EntityManager</literal>. Within a persistence
context, the application may safely use <literal>==</literal> to compare
entities.</para>
<para>However, an application that uses <literal>==</literal> outside of
a persistence context might see unexpected results. This might occur
even in some unexpected places, for example, if you put two detached
instances into the same <literal>Set</literal>. Both might have the same
database identity (i.e. they represent the same row), but JVM identity
is by definition not guaranteed for instances in detached state. The
developer has to override the <literal>equals()</literal> and
<literal>hashCode()</literal> methods in persistent classes and
implement his own notion of object equality. There is one caveat: Never
use the database identifier to implement equality, use a business key, a
combination of unique, usually immutable, attributes. The database
identifier will change if a transient entity is made persistent (see the
contract of the <literal>persist()</literal> operation). If the
transient instance (usually together with detached instances) is held in
a <literal>Set</literal>, changing the hashcode breaks the contract of
the <literal>Set</literal>. Attributes for good business keys don't have
to be as stable as database primary keys, you only have to guarantee
stability as long as the objects are in the same <literal>Set</literal>.
See the Hibernate website for a more thorough discussion of this issue.
Also note that this is not a Hibernate issue, but simply how Java object
identity and equality has to be implemented.</para>
</sect2>
<sect2 id="transactions-basics-issues">
<title>Common concurrency control issues</title>
<para>Never use the anti-patterns
<emphasis>entitymanager-per-user-session</emphasis> or
<emphasis>entitymanager-per-application</emphasis> (of course, there are
rare exceptions to this rule, e.g. entitymanager-per-application might
be acceptable in a desktop application, with manual flushing of the
persistence context). Note that some of the following issues might also
appear with the recommended patterns, make sure you understand the
implications before making a design decision:</para>
<itemizedlist>
<listitem>
<para>An entity manager is not thread-safe. Things which are
supposed to work concurrently, like HTTP requests, session beans, or
Swing workers, will cause race conditions if an
<literal>EntityManager</literal> instance would be shared. If you
keep your Hibernate <literal>EntityManager</literal> in your
<literal>HttpSession</literal> (discussed later), you should
consider synchronizing access to your Http session. Otherwise, a
user that clicks reload fast enough may use the same
<literal>EntityManager</literal> in two concurrently running
threads. You will very likely have provisions for this case already
in place, for other non-threadsafe but session-scoped
objects.</para>
</listitem>
<listitem>
<para>An exception thrown by the Entity Manager means you have to
rollback your database transaction and close the
<literal>EntityManager</literal> immediately (discussed later in
more detail). If your <literal>EntityManager</literal> is bound to
the application, you have to stop the application. Rolling back the
database transaction doesn't put your business objects back into the
state they were at the start of the transaction. This means the
database state and the business objects do get out of sync. Usually
this is not a problem, because exceptions are not recoverable and
you have to start over your unit of work after rollback
anyway.</para>
</listitem>
<listitem>
<para>The persistence context caches every object that is in managed
state (watched and checked for dirty state by Hibernate). This means
it grows endlessly until you get an
<classname>OutOfMemoryException</classname>, if you keep it open for
a long time or simply load too much data. One solution for this is
some kind batch processing with regular flushing of the persistence
context, but you should consider using a database stored procedure
if you need mass data operations. Some solutions for this problem
are shown in <xref linkend="batch" />. Keeping a persistence context
open for the duration of a user session also means a high
probability of stale data, which you have to know about and control
appropriately.</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 id="transactions-demarcation">
<title>Database transaction demarcation</title>
<para>Database (or system) transaction boundaries are always necessary. No
communication with the database can occur outside of a database
transaction (this seems to confuse many developers who are used to the
auto-commit mode). Always use clear transaction boundaries, even for
read-only operations. Depending on your isolation level and database
capabilities this might not be required but there is no downside if you
always demarcate transactions explicitly. You'll have to do operations
outside a transaction, though, when you'll need to retain modifications in
an <literal>EXTENDED</literal> persistence context.</para>
<para>A JPA application can run in non-managed (i.e. standalone, simple
Web- or Swing applications) and managed Java EE environments. In a
non-managed environment, an <literal>EntityManagerFactory</literal> is
usually responsible for its own database connection pool. The application
developer has to manually set transaction boundaries, in other words,
begin, commit, or rollback database transactions itself. A managed
environment usually provides container-managed transactions, with the
transaction assembly defined declaratively through annotations of EJB
session beans, for example. Programmatic transaction demarcation is then
no longer necessary, even flushing the <literal>EntityManager</literal> is
done automatically.</para>
<para>Usually, ending a unit of work involves four distinct phases:</para>
<itemizedlist spacing="compact">
<listitem>
<para>commit the (resource-local or JTA) transaction (this
automatically flushes the entity manager and persistence
context)</para>
</listitem>
<listitem>
<para>close the entity manager (if using an application-managed entity
manager)</para>
</listitem>
<listitem>
<para>handle exceptions</para>
</listitem>
</itemizedlist>
<para>We'll now have a closer look at transaction demarcation and
exception handling in both managed- and non-managed environments.</para>
<sect2 id="transactions-demarcation-nonmanaged">
<title>Non-managed environment</title>
<para>If an JPA persistence layer runs in a non-managed environment,
database connections are usually handled by Hibernate's pooling
mechanism behind the scenes. The common entity manager and transaction
handling idiom looks like this:</para>
<programlisting role="JAVA" language="JAVA">// Non-managed environment idiom
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
try {
tx = em.getTransaction();
tx.begin();
// do some work
...
tx.commit();
}
catch (RuntimeException e) {
if ( tx != null &amp;&amp; tx.isActive() ) tx.rollback();
throw e; // or display error message
}
finally {
em.close();
}</programlisting>
<para>You don't have to <literal>flush()</literal> the
<literal>EntityManager</literal> explicitly - the call to
<literal>commit()</literal> automatically triggers the
synchronization.</para>
<para>A call to <literal>close()</literal> marks the end of an
<literal>EntityManager</literal>. The main implication of
<literal>close()</literal> is the release of resources - make sure you
always close and never outside of guaranteed finally block.</para>
<para>You will very likely never see this idiom in business code in a
normal application; fatal (system) exceptions should always be caught at
the "top". In other words, the code that executes entity manager calls
(in the persistence layer) and the code that handles
<literal>RuntimeException</literal> (and usually can only clean up and
exit) are in different layers. This can be a challenge to design
yourself and you should use J2EE/EJB container services whenever they
are available. Exception handling is discussed later in this
chapter.</para>
<sect3>
<title>EntityTransaction</title>
<para>In a JTA environment, you don't need any extra API to interact
with the transaction in your environment. Simply use transaction
declaration or the JTA APIs.</para>
<para>If you are using a <literal>RESOURCE_LOCAL</literal> entity
manager, you need to demarcate your transaction boundaries through the
<literal>EntityTransaction</literal> API. You can get an
<literal>EntityTransaction</literal> through
<literal>entityManager.getTransaction()</literal>. This
<literal>EntityTransaction</literal> API provides the regular
<methodname>begin()</methodname>, <methodname>commit()</methodname>,
<methodname>rollback()</methodname> and
<methodname>isActive()</methodname> methods. It also provide a way to
mark a transaction as rollback only, ie force the transaction to
rollback. This is very similar to the JTA operation
<methodname>setRollbackOnly()</methodname>. When a
<literal>commit()</literal> operation fail and/or if the transaction
is marked as <literal>setRollbackOnly()</literal>, the
<literal>commit()</literal> method will try to rollback the
transaction and raise a
<literal>javax.transaction.RollbackException</literal>.</para>
<para>In a <literal>JTA</literal> entity manager,
<literal>entityManager.getTransaction()</literal> calls are not
permitted.</para>
</sect3>
</sect2>
<sect2 id="transactions-demarcation-jta">
<title>Using JTA</title>
<para>If your persistence layer runs in an application server (e.g.
behind EJB3 session beans), every datasource connection obtained
internally by the entity manager will automatically be part of the
global JTA transaction. Hibernate offers two strategies for this
integration.</para>
<para>If you use bean-managed transactions (BMT), the code will look
like this:</para>
<programlisting role="JAVA" language="JAVA">// BMT idiom
@Resource public UserTransaction utx;
@Resource public EntityManagerFactory factory;
public void doBusiness() {
EntityManager em = factory.createEntityManager();
try {
// do some work
...
utx.commit();
}
catch (RuntimeException e) {
if (utx != null) utx.rollback();
throw e; // or display error message
}
finally {
em.close();
}</programlisting>
<para>With Container Managed Transactions (CMT) in an EJB3 container,
transaction demarcation is done in session bean annotations or
deployment descriptors, not programatically. The
<literal>EntityManager</literal> will automatically be flushed on
transaction completion (and if you have injected or lookup the
<literal>EntityManager</literal>, it will be also closed automatically).
If an exception occurs during the <literal>EntityManager</literal> use,
transaction rollback occurs automatically if you don't catch the
exception. Since <literal>EntityManager</literal> exceptions are
<literal>RuntimeException</literal>s they will rollback the transaction
as per the EJB specification (system exception vs. application
exception).</para>
<para>It is important to let Hibernate EntityManager define the
<literal>hibernate.transaction.factory_class</literal> (ie not
overriding this value). Remember to also set
<literal>org.hibernate.transaction.manager_lookup_class</literal>.</para>
<para>If you work in a CMT environment, you might also want to use the
same entity manager in different parts of your code. Typically, in a
non-managed environment you would use a <literal>ThreadLocal</literal>
variable to hold the entity manager, but a single EJB request might
execute in different threads (e.g. session bean calling another session
bean). The EJB3 container takes care of the persistence context
propagation for you. Either using injection or lookup, the EJB3
container will return an entity manager with the same persistence
context bound to the JTA context if any, or create a new one and bind it
(see <xref linkend="architecture-ejb-persistctxpropagation" /> .)</para>
<para>Our entity manager/transaction management idiom for CMT and EJB3
container-use is reduced to this:</para>
<programlisting role="JAVA" language="JAVA">//CMT idiom through injection
@PersistenceContext(name="sample") EntityManager em;</programlisting>
<para>Or this if you use Java Context and Dependency Injection
(CDI).</para>
<programlisting role="JAVA" language="JAVA">@Inject EntityManager em;</programlisting>
<para>In other words, all you have to do in a managed environment is to
inject the <literal>EntityManager</literal>, do your data access work,
and leave the rest to the container. Transaction boundaries are set
declaratively in the annotations or deployment descriptors of your
session beans. The lifecycle of the entity manager and persistence
context is completely managed by the container.</para>
<para>Due to a silly limitation of the JTA spec, it is not possible for
Hibernate to automatically clean up any unclosed
<literal>ScrollableResults</literal> or <literal>Iterator</literal>
instances returned by <literal>scroll()</literal> or
<literal>iterate()</literal>. You <emphasis>must</emphasis> release the
underlying database cursor by calling
<literal>ScrollableResults.close()</literal> or
<literal>Hibernate.close(Iterator)</literal> explicitly from a
<literal>finally</literal> block. (Of course, most applications can
easily avoid using <literal>scroll()</literal> or
<literal>iterate()</literal> at all from the CMT code.)</para>
</sect2>
<sect2 id="transactions-demarcation-exceptions">
<title>Exception handling</title>
<para>If the <literal>EntityManager</literal> throws an exception
(including any <literal>SQLException</literal>), you should immediately
rollback the database transaction, call
<literal>EntityManager.close()</literal> (if
<methodname>createEntityManager()</methodname> has been called) and
discard the <literal>EntityManager</literal> instance. Certain methods
of <literal>EntityManager</literal> will <emphasis>not</emphasis> leave
the persistence context in a consistent state. No exception thrown by an
entity manager can be treated as recoverable. Ensure that the
<literal>EntityManager</literal> will be closed by calling
<literal>close()</literal> in a <literal>finally</literal> block. Note
that a container managed entity manager will do that for you. You just
have to let the RuntimeException propagate up to the container.</para>
<para>The Hibernate entity manager generally raises exceptions which
encapsulate the Hibernate core exception. Common exceptions raised by
the <literal>EntityManager</literal> API are</para>
<itemizedlist>
<listitem>
<para><classname>IllegalArgumentException</classname>: something
wrong happen</para>
</listitem>
<listitem>
<para><classname>EntityNotFoundException</classname>: an entity was
expected but none match the requirement</para>
</listitem>
<listitem>
<para><classname>NonUniqueResultException</classname>: more than one
entity is found when calling
<methodname>getSingleResult()</methodname></para>
</listitem>
<listitem>
<para>NoResultException: when
<methodname>getSingleResult()</methodname> does not find any
matching entity</para>
</listitem>
<listitem>
<para><classname>EntityExistsException</classname>: an existing
entity is passed to <methodname>persist()</methodname></para>
</listitem>
<listitem>
<para><classname>TransactionRequiredException</classname>: this
operation has to be in a transaction</para>
</listitem>
<listitem>
<para><classname>IllegalStateException</classname>: the entity
manager is used in a wrong way</para>
</listitem>
<listitem>
<para><classname>RollbackException</classname>: a failure happens
during <methodname>commit()</methodname></para>
</listitem>
<listitem>
<para><classname>QueryTimeoutException</classname>: the query takes
longer than the specified timeout (see
<literal>javax.persistence.query.timeout</literal> - this property
is a hint and might not be followed)</para>
</listitem>
<listitem>
<para><classname>PessimisticLockException</classname>: when a lock
cannot be acquired</para>
</listitem>
<listitem>
<para><classname>OptimisticLockException</classname>: an optimistic
lock is failing</para>
</listitem>
<listitem>
<para><classname>LockTimeoutException</classname>: when a lock takes
longer than the expected time to be acquired
(<literal>javax.persistence.lock.timeout</literal> in
milliseconds)</para>
</listitem>
<listitem>
<para><classname>TransactionRequiredException</classname>: an
operation requiring a transaction is executed outside of a
transaction</para>
</listitem>
</itemizedlist>
<para>The <literal>HibernateException</literal>, which wraps most of the
errors that can occur in a Hibernate persistence layer, is an unchecked
exception. Note that Hibernate might also throw other unchecked
exceptions which are not a <literal>HibernateException</literal>. These
are, again, not recoverable and appropriate action should be
taken.</para>
<para>Hibernate wraps <literal>SQLException</literal>s thrown while
interacting with the database in a <literal>JDBCException</literal>. In
fact, Hibernate will attempt to convert the exception into a more
meaningful subclass of <literal>JDBCException</literal>. The underlying
<literal>SQLException</literal> is always available via
<literal>JDBCException.getCause()</literal>. Hibernate converts the
<literal>SQLException</literal> into an appropriate
<literal>JDBCException</literal> subclass using the
<literal>SQLExceptionConverter</literal> attached to the
<literal>SessionFactory</literal>. By default, the
<literal>SQLExceptionConverter</literal> is defined by the configured
dialect; however, it is also possible to plug in a custom implementation
(see the javadocs for the
<literal>SQLExceptionConverterFactory</literal> class for details). The
standard <literal>JDBCException</literal> subtypes are:</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>JDBCConnectionException</literal> - indicates an
error with the underlying JDBC communication.</para>
</listitem>
<listitem>
<para><literal>SQLGrammarException</literal> - indicates a grammar
or syntax problem with the issued SQL.</para>
</listitem>
<listitem>
<para><literal>ConstraintViolationException</literal> - indicates
some form of integrity constraint violation.</para>
</listitem>
<listitem>
<para><literal>LockAcquisitionException</literal> - indicates an
error acquiring a lock level necessary to perform the requested
operation.</para>
</listitem>
<listitem>
<para><literal>GenericJDBCException</literal> - a generic exception
which did not fall into any of the other categories.</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1>
<title>EXTENDED Persistence Context</title>
<para>All application managed entity manager and container managed
persistence contexts defined as such are <literal>EXTENDED</literal>. This
means that the persistence context type goes beyond the transaction life
cycle. We should then understand what happens to operations made outside
the scope of a transaction.</para>
<para>In an <literal>EXTENDED</literal> persistence context, all read only
operations of the entity manager can be executed outside a transaction
(<literal>find()</literal>, <literal>getReference()</literal>,
<literal>refresh()</literal>, <methodname>detach()</methodname> and read
queries). Some modifications operations can be executed outside a
transaction, but they are queued until the persistence context join a
transaction: this is the case of <literal>persist()</literal>,
<literal><literal>merge()</literal></literal>,
<literal>remove()</literal>. Some operations cannot be called outside a
transaction: <literal>flush()</literal>, <literal>lock()</literal>, and
update/delete queries.</para>
<sect2>
<title>Container Managed Entity Manager</title>
<para>When using an <literal>EXTENDED</literal> persistence context with
a container managed entity manager, the lifecycle of the persistence
context is binded to the lifecycle of the Stateful Session Bean. Plus if
the entity manager is created outside a transaction, modifications
operations (persist, merge, remove) are queued in the persistence
context and not executed to the database.</para>
<para>When a method of the stateful session bean involved or starting a
transaction is later called, the entity manager join the transaction.
All queued operation will then be executed to synchronize the
persistence context.</para>
<para>This is perfect to implement the
<literal>entitymanager-per-conversation</literal> pattern. A stateful
session bean represents the conversation implementation. All
intermediate conversation work will be processed in methods not
involving transaction. The end of the conversation will be processed
inside a <literal>JTA</literal> transaction. Hence all queued operations
will be executed to the database and committed. If you are interested in
the notion of conversation inside your application, have a look at JBoss
Seam. JBoss Seam emphasizes the concept of conversation and entity
manager lifecycle and bind EJB3 and JSF together.</para>
</sect2>
<sect2>
<title>Application Managed Entity Manager</title>
<para>Application-managed entity manager are always
<literal>EXTENDED</literal>. When you create an entity manager inside a
transaction, the entity manager automatically join the current
transaction. If the entity manager is created outside a transaction, the
entity manager will queue the modification operations. When</para>
<itemizedlist>
<listitem>
<para><methodname>entityManager.joinTransaction()</methodname> is
called when a JTA transaction is active for a <literal>JTA</literal>
entity manager</para>
</listitem>
<listitem>
<para><literal>entityManager.getTransaction().begin()</literal> is
called for a <literal>RESOURCE_LOCAL</literal> entity manager</para>
</listitem>
</itemizedlist>
<para>the entity manager join the transaction and all the queued
operations will then be executed to synchronize the persistence
context.</para>
<para>It is not legal to call
<methodname>entityManager.joinTransaction()</methodname> if no JTA
transaction is involved.</para>
</sect2>
</sect1>
<sect1 id="transactions-optimistic">
<title>Optimistic concurrency control</title>
<para>The only approach that is consistent with high concurrency and high
scalability is optimistic concurrency control with versioning. Version
checking uses version numbers, or timestamps, to detect conflicting
updates (and to prevent lost updates). Hibernate provides for three
possible approaches to writing application code that uses optimistic
concurrency. The use cases we show are in the context of long application
transactions but version checking also has the benefit of preventing lost
updates in single database transactions.</para>
<sect2 id="transactions-optimistic-manual">
<title>Application version checking</title>
<para>In an implementation without much help from the persistence
mechanism, each interaction with the database occurs in a new
<literal>EntityManager</literal> and the developer is responsible for
reloading all persistent instances from the database before manipulating
them. This approach forces the application to carry out its own version
checking to ensure application transaction isolation. This approach is
the least efficient in terms of database access. It is the approach most
similar to EJB2 entities:</para>
<programlisting role="JAVA" language="JAVA">// foo is an instance loaded by a previous entity manager
em = factory.createEntityManager();
EntityTransaction t = em.getTransaction();
t.begin();
int oldVersion = foo.getVersion();
Foo dbFoo = em.find( foo.getClass(), foo.getKey() ); // load the current state
if ( dbFoo.getVersion()!=foo.getVersion ) throw new StaleObjectStateException();
dbFoo.setProperty("bar");
t.commit();
em.close();</programlisting>
<para>The <literal>version</literal> property is mapped using
<literal>@Version</literal>, and the entity manager will automatically
increment it during flush if the entity is dirty.</para>
<para>Of course, if you are operating in a low-data-concurrency
environment and don't require version checking, you may use this
approach and just skip the version check. In that case, <emphasis>last
commit wins</emphasis> will be the default strategy for your long
application transactions. Keep in mind that this might confuse the users
of the application, as they might experience lost updates without error
messages or a chance to merge conflicting changes.</para>
<para>Clearly, manual version checking is only feasible in very trivial
circumstances and not practical for most applications. Often not only
single instances, but complete graphs of modified objects have to be
checked. Hibernate offers automatic version checking with either
detached instances or an extended entity manager and persistence context
as the design paradigm.</para>
</sect2>
<sect2 id="transactions-optimistic-longsession">
<title>Extended entity manager and automatic versioning</title>
<para>A single persistence context is used for the whole application
transaction. The entity manager checks instance versions at flush time,
throwing an exception if concurrent modification is detected. It's up to
the developer to catch and handle this exception (common options are the
opportunity for the user to merge his changes or to restart the business
process with non-stale data).</para>
<para>In an <literal>EXTENDED</literal> persistence context, all
operations made outside an active transaction are queued. The
<literal>EXTENDED</literal> persistence context is flushed when executed
in an active transaction (at worse at commit time).</para>
<para>The <literal>Entity Manager</literal> is disconnected from any
underlying JDBC connection when waiting for user interaction. In an
application-managed extended entity manager, this occurs automatically
at transaction completion. In a stateful session bean holding a
container-managed extended entity manager (i.e. a SFSB annotated with
<literal>@PersistenceContext(EXTENDED)</literal>), this occurs
transparently as well. This approach is the most efficient in terms of
database access. The application need not concern itself with version
checking or with merging detached instances, nor does it have to reload
instances in every database transaction. For those who might be
concerned by the number of connections opened and closed, remember that
the connection provider should be a connection pool, so there is no
performance impact. The following examples show the idiom in a
non-managed environment:</para>
<programlisting role="JAVA" language="JAVA">// foo is an instance loaded earlier by the extended entity manager
em.getTransaction.begin(); // new connection to data store is obtained and tx started
foo.setProperty("bar");
em.getTransaction().commit(); // End tx, flush and check version, disconnect</programlisting>
<para>The <literal>foo</literal> object still knows which
<literal>persistence context</literal> it was loaded in. With
<literal>getTransaction.begin();</literal> the entity manager obtains a
new connection and resumes the persistence context. The method
<literal>getTransaction().commit()</literal> will not only flush and
check versions, but also disconnects the entity manager from the JDBC
connection and return the connection to the pool.</para>
<para>This pattern is problematic if the persistence context is too big
to be stored during user think time, and if you don't know where to
store it. E.g. the <literal>HttpSession</literal> should be kept as
small as possible. As the persistence context is also the (mandatory)
first-level cache and contains all loaded objects, we can probably use
this strategy only for a few request/response cycles. This is indeed
recommended, as the persistence context will soon also have stale
data.</para>
<para>It is up to you where you store the extended entity manager during
requests, inside an EJB3 container you simply use a stateful session
bean as described above. Don't transfer it to the web layer (or even
serialize it to a separate tier) to store it in the
<literal>HttpSession</literal>. In a non-managed, two-tiered environment
the <literal>HttpSession</literal> might indeed be the right place to
store it.</para>
</sect2>
<sect2 id="transactions-optimistic-detached">
<title>Detached objects and automatic versioning</title>
<para>With this paradigm, each interaction with the data store occurs in
a new persistence context. However, the same persistent instances are
reused for each interaction with the database. The application
manipulates the state of detached instances originally loaded in another
persistence context and then merges the changes using
<literal>EntityManager.merge()</literal>:</para>
<programlisting role="JAVA" language="JAVA">// foo is an instance loaded by a non-extended entity manager
foo.setProperty("bar");
entityManager = factory.createEntityManager();
entityManager.getTransaction().begin();
managedFoo = session.merge(foo); // discard foo and from now on use managedFoo
entityManager.getTransaction().commit();
entityManager.close();</programlisting>
<para>Again, the entity manager will check instance versions during
flush, throwing an exception if conflicting updates occurred.</para>
</sect2>
</sect1>
</chapter>

View File

@ -1,291 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2010, Red Hat Inc or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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">
<chapter id="architecture">
<title>Architecture</title>
<section>
<title>Definitions</title>
<para>JPA 2 is part of the Java EE 6.0 platform. Persistence in JPA is
available in containers like EJB 3 or the more modern CDI (Java Context
and Dependency Injection), as well as in standalone Java SE applications
that execute outside of a particular container. The following programming
interfaces and artifacts are available in both environments.</para>
<variablelist spacing="compact">
<varlistentry>
<term><literal>EntityManagerFactory</literal></term>
<listitem>
<para>An entity manager factory provides entity manager instances,
all instances are configured to connect to the same database, to use
the same default settings as defined by the particular
implementation, etc. You can prepare several entity manager
factories to access several data stores. This interface is similar
to the <literal>SessionFactory</literal> in native Hibernate.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>EntityManager</literal></term>
<listitem>
<para>The <literal>EntityManager</literal> API is used to access a
database in a particular unit of work. It is used to create and
remove persistent entity instances, to find entities by their
primary key identity, and to query over all entities. This interface
is similar to the <literal>Session</literal> in Hibernate.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Persistence context</term>
<listitem>
<para>A persistence context is a set of entity instances in which
for any persistent entity identity there is a unique entity
instance. Within the persistence context, the entity instances and
their lifecycle is managed by a particular entity manager. The scope
of this context can either be the transaction, or an extended unit
of work.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Persistence unit</term>
<listitem>
<para>The set of entity types that can be managed by a given entity
manager is defined by a persistence unit. A persistence unit defines
the set of all classes that are related or grouped by the
application, and which must be collocated in their mapping to a
single data store.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Container-managed entity manager</term>
<listitem>
<para>An Entity Manager whose lifecycle is managed by the
container</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Application-managed entity manager</term>
<listitem>
<para>An Entity Manager whose lifecycle is managed by the
application.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>JTA entity manager</term>
<listitem>
<para>Entity manager involved in a JTA transaction</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Resource-local entity manager</term>
<listitem>
<para>Entity manager using a resource transaction (not a JTA
transaction).</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section>
<title>In container environment (eg. EJB 3)</title>
<section>
<title>Container-managed entity manager</title>
<para>The most common and widely used entity manager in a Java EE
environment is the container-managed entity manager. In this mode, the
container is responsible for the opening and closing of the entity
manager (this is transparent to the application). It is also responsible
for transaction boundaries. A container-managed entity manager is
obtained in an application through dependency injection or through JNDI
lookup, A container-managed entity manger requires the use of a JTA
transaction.</para>
</section>
<section>
<title>Application-managed entity manager</title>
<para>An application-managed entity manager allows you to control the
entity manager in application code. This entity manager is retrieved
through the <literal>EntityManagerFactory</literal> API. An application
managed entity manager can be either involved in the current JTA
transaction (a JTA entity manager), or the transaction may be controlled
through the <literal>EntityTransaction</literal> API (a resource-local
entity manager). The resource-local entity manager transaction maps to a
direct resource transaction (i. e. in Hibernate's case a JDBC
transaction). The entity manager type (JTA or resource-local) is defined
at configuration time, when setting up the entity manager
factory.</para>
</section>
<section id="architecture-ejb-persistctxscope">
<title>Persistence context scope</title>
<para>An entity manager is the API to interact with the persistence
context. Two common strategies can be used: binding the persistence
context to the transaction boundaries, or keeping the persistence
context available across several transactions.</para>
<para>The most common case is to bind the persistence context scope to
the current transaction scope. This is only doable when JTA transactions
are used: the persistence context is associated with the JTA transaction
life cycle. When an entity manager is invoked, the persistence context
is also opened, if there is no persistence context associated with the
current JTA transaction. Otherwise, the associated persistence context
is used. The persistence context ends when the JTA transaction
completes. This means that during the JTA transaction, an application
will be able to work on managed entities of the same persistence
context. In other words, you don't have to pass the entity manager's
persistence context across your managed beans (CDI) or EJBs method
calls, but simply use dependency injection or lookup whenever you need
an entity manager.</para>
<para>You can also use an extended persistence context. This can be
combined with stateful session beans, if you use a container-managed
entity manager: the persistence context is created when an entity
manager is retrieved from dependency injection or JNDI lookup , and is
kept until the container closes it after the completion of the
<literal>Remove</literal> stateful session bean method. This is a
perfect mechanism for implementing a "long" unit of work pattern. For
example, if you have to deal with multiple user interaction cycles as a
single unit of work (e.g. a wizard dialog that has to be fully
completed), you usually model this as a unit of work from the point of
view of the application user, and implement it using an extended
persistence context. Please refer to the Hibernate reference manual or
the book Hibernate In Action for more information about this pattern.
</para>
<para>JBoss Seam 3 is built on top of CDI and has at it's core concept
the notion of conversation and unit of work. For an application-managed
entity manager the persistence context is created when the entity
manager is created and kept until the entity manager is closed. In an
extended persistence context, all modification operations (persist,
merge, remove) executed outside a transaction are queued until the
persistence context is attached to a transaction. The transaction
typically occurs at the user process end, allowing the whole process to
be committed or rollbacked. For application-managed entity manager only
support the extended persistence context.</para>
<para>A resource-local entity manager or an entity manager created with
<literal>EntityManagerFactory.createEntityManager()</literal>
(application-managed) has a one-to-one relationship with a persistence
context. In other situations <emphasis>persistence context
propagation</emphasis> occurs.</para>
</section>
<section id="architecture-ejb-persistctxpropagation">
<title>Persistence context propagation</title>
<para>Persistence context propagation occurs for container-managed
entity managers.</para>
<para>In a transaction-scoped container managed entity manager (common
case in a Java EE environment), the JTA transaction propagation is the
same as the persistence context resource propagation. In other words,
container-managed transaction-scoped entity managers retrieved within a
given JTA transaction all share the same persistence context. In
Hibernate terms, this means all managers share the same session.</para>
<para>Important: persistence context are never shared between different
JTA transactions or between entity manager that do not came from the
same entity manager factory. There are some noteworthy exceptions for
context propagation when using extended persistence contexts:</para>
<itemizedlist>
<listitem>
<para>If a stateless session bean, message-driven bean, or stateful
session bean with a transaction-scoped persistence context calls a
stateful session bean with an extended persistence context in the
same JTA transaction, an
<classname>IllegalStateException</classname> is thrown.</para>
</listitem>
<listitem>
<para>If a stateful session bean with an extended persistence
context calls as stateless session bean or a stateful session bean
with a transaction-scoped persistence context in the same JTA
transaction, the persistence context is propagated.</para>
</listitem>
<listitem>
<para>If a stateful session bean with an extended persistence
context calls a stateless or stateful session bean in a different
JTA transaction context, the persistence context is not
propagated.</para>
</listitem>
<listitem>
<para>If a stateful session bean with an extended persistence
context instantiates another stateful session bean with an extended
persistence context, the extended persistence context is inherited
by the second stateful session bean. If the second stateful session
bean is called with a different transaction context than the first,
an IllegalStateException is thrown.</para>
</listitem>
<listitem>
<para>If a stateful session bean with an extended persistence
context calls a stateful session bean with a different extended
persistence context in the same transaction, an
<classname>IllegalStateException</classname> is thrown.</para>
</listitem>
</itemizedlist>
</section>
</section>
<section id="architecture-javase" revision="1">
<title>Java SE environments</title>
<para>In a Java SE environment only extended context application-managed
entity managers are available. You can retrieve an entity manger using the
<literal>EntityManagerFactory</literal> API. Only resource-local entity
managers are available. In other words, JTA transactions and persistence
context propagation are not supported in Java SE (you will have to
propagate the persistence context yourself, e.g. using the thread local
session pattern popular in the Hibernate community).</para>
<para>Extended context means that a persistence context is created when
the entity manager is retrieved (using
<literal>EntityManagerFactory.createEntityManager(...)</literal> ) and
closed when the entity manager is closed. Many resource-local transaction
share the same persistence context, in this case.</para>
</section>
</chapter>

View File

@ -1,240 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2010, Red Hat Inc. or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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" [
<!ENTITY aptUrl 'http://java.sun.com/javase/6/docs/technotes/tools/solaris/javac.html#processing'>
]>
<chapter id="metamodel">
<title>Metamodel</title>
<note>
<para>
The Metamodel itself is described in <citetitle pubwork="chapter">Chapter 5 Metamodel API</citetitle>
of the <citation><xref linkend="JPA2"/></citation>. <citetitle pubwork="chapter">Chapter 6 Criteria API</citetitle>
of the <citation><xref linkend="JPA2"/></citation> describes and shows uses of the metamodel in criteria
queries, as does <xref linkend="querycriteria"/>.
</para>
</note>
<para>
The metamodel is a set of objects that describe your domain model.
<interfacename>javax.persistence.metamodel.Metamodel</interfacename> acts as a repository of these metamodel
objects and provides access to them, and can be obtained from either the
<interfacename>javax.persistence.EntityManagerFactory</interfacename> or the
<interfacename>javax.persistence.EntityManager</interfacename> via their
<methodname>getMetamodel</methodname> method.
</para>
<para>
This metamodel is important in 2 ways. First, it allows providers and frameworks a generic way to
deal with an application's domain model. Persistence providers will already have some form of
metamodel that they use to describe the domain model being mapped. This API however defines a single,
independent access to that existing information. A validation framework, for example, could use this
information to understand associations; a marshaling framework might use this information to decide how
much of an entity graph to marshal. This usage is beyond the scope of this documentation.
</para>
<important>
<para>
As of today the JPA 2 metamodel does not provide any facility for accessing relational information
pertaining to the physical model. It is expected this will be addressed in a future release of the
specification.
</para>
</important>
<para>
Second, from an application writer's perspective, it allows very fluent expression of completely type-safe
criteria queries, especially the <emphasis>Static Metamodel</emphasis> approach. The
<citation><xref linkend="JPA2"/></citation> defines a number of ways the metamodel can be accessed and used,
including the <emphasis>Static Metamodel</emphasis> approach, which we will look at later.
The <emphasis>Static Metamodel</emphasis> approach is wonderful when the code has
<ulink url="http://en.wikipedia.org/wiki/A_priori_and_a_posteriori">a priori knowledge</ulink> of the domain
model. <xref linkend="querycriteria"/> uses this approach exclusively in its examples.
</para>
<section id="metamodel-static">
<title>Static metamodel</title>
<para>
A <emphasis>static metamodel</emphasis> is a series of classes that "mirror" the entities and embeddables
in the domain model and provide static access to the metadata about the mirrored class's attributes. We
will exclusively discuss what the <citation><xref linkend="JPA2"/></citation> terms a
<emphasis>Canonical Metamodel</emphasis>:
</para>
<blockquote>
<attribution>
<citation><xref linkend="JPA2"/>, section 6.2.1.1, pp 198-199</citation>
</attribution>
<para>
<itemizedlist>
<listitem>
<para>
For each managed class <classname>X</classname> in package <package>p</package>,
a metamodel class <classname>X_</classname> in package <package>p</package> is created.
</para>
</listitem>
<listitem>
<para>
The name of the metamodel class is derived from the name of the managed class by appending
"_" to the name of the managed class.
</para>
</listitem>
<listitem>
<para>
The metamodel class <classname>X_</classname> must be annotated with the
<interfacename>javax.persistence.StaticMetamodel</interfacename>annotation
<footnote>
<para>
<emphasis>(from the original)</emphasis> If the class was generated, the
<interfacename>javax.annotation.Generated</interfacename> annotation should be
used to annotate the class. The use of any other annotations on static metamodel
classes is undefined.
</para>
</footnote>
</para>
</listitem>
<listitem>
<para>
If class <classname>X</classname> extends another class <classname>S</classname>, where
<classname>S</classname> is the most derived managed class (i.e., entity or mapped
superclass) extended by <classname>X</classname>, then class <classname>X_</classname> must
extend class <classname>S_</classname>, where <classname>S_</classname> is the metamodel
class created for <classname>S</classname>.
</para>
</listitem>
<listitem>
<para>
For every persistent non-collection-valued attribute <emphasis>y</emphasis> declared by
class <classname>X</classname>, where the type of <emphasis>y</emphasis> is
<classname>Y</classname>, the metamodel class must contain a declaration as follows:
<programlisting><![CDATA[public static volatile SingularAttribute<X, Y> y;]]></programlisting>
</para>
</listitem>
<listitem>
<para>
For every persistent collection-valued attribute <emphasis>z</emphasis> declared by class
<classname>X</classname>, where the element type of <emphasis>z</emphasis> is
<classname>Z</classname>, the metamodel class must contain a declaration as follows:
<itemizedlist>
<listitem>
<para>
if the collection type of <emphasis>z</emphasis> is
<interfacename>java.util.Collection</interfacename>, then
<programlisting><![CDATA[public static volatile CollectionAttribute<X, Z> z;]]></programlisting>
</para>
</listitem>
<listitem>
<para>
if the collection type of <emphasis>z</emphasis> is
<interfacename>java.util.Set</interfacename>, then
<programlisting><![CDATA[public static volatile SetAttribute<X, Z> z;]]></programlisting>
</para>
</listitem>
<listitem>
<para>
if the collection type of <emphasis>z</emphasis> is
<interfacename>java.util.List</interfacename>, then
<programlisting><![CDATA[public static volatile ListAttribute<X, Z> z;]]></programlisting>
</para>
</listitem>
<listitem>
<para>
if the collection type of <emphasis>z</emphasis> is
<interfacename>java.util.Map</interfacename>, then
<programlisting><![CDATA[public static volatile MapAttribute<X, K, Z> z;]]></programlisting>
where <classname>K</classname> is the type of the key of the map in class
<classname>X</classname>
</para>
</listitem>
</itemizedlist>
</para>
</listitem>
</itemizedlist>
</para>
<para>
Import statements must be included for the needed <package>javax.persistence.metamodel</package> types
as appropriate (e.g., <interfacename>javax.persistence.metamodel.SingularAttribute</interfacename>,
<interfacename>javax.persistence.metamodel.CollectionAttribute</interfacename>,
<interfacename>javax.persistence.metamodel.SetAttribute</interfacename>,
<interfacename>javax.persistence.metamodel.ListAttribute</interfacename>,
<interfacename>javax.persistence.metamodel.MapAttribute</interfacename>) and all classes
<classname>X</classname>, <classname>Y</classname>, <classname>Z</classname>, and <classname>K</classname>.
</para>
</blockquote>
<example id="metamodel-static-ex">
<title>Static metamodel example</title>
<para>
For the <classname>Person</classname> entity
<programlisting><![CDATA[package org.hibernate.jpa2.metamodel.example;
import java.util.Set;
import javax.persistence.Entity;
@Entity
public class Person {
@Id private Long id;
private String name;
private int age;
private Address address;
@OneToMany private Set<Order> orders;
}]]></programlisting>
The corresponding canonical metamodel class, <classname>Person_</classname> would look like
<programlisting><![CDATA[package org.hibernate.jpa2.metamodel.example;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.StaticMetamodel;
@StaticMetamodel( Person.class )
public class Person_ {
public static volatile SingularAttribute<Person, Long> id;
public static volatile SingularAttribute<Person, String> name;
public static volatile SingularAttribute<Person, Integer> age;
public static volatile SingularAttribute<Person, Address> address;
public static volatile SetAttribute<Person, Order> orders;
}]]></programlisting>
</para>
</example>
<note>
<para>
These canonical metamodel classes can be generated manually if you wish though it is expected
that most developers will prefer use of an <ulink url="&aptUrl;">annotation processor</ulink>.
Annotation processors themselves are beyond the scope of this document. However, the Hibernate team
does develop an annotation processor tool for generating a canonical metamodel.
See <citetitle>Hibernate Metamodel Generator</citetitle>.
</para>
</note>
<para>
When the Hibernate <interfacename>EntityManagerFactory</interfacename> is being built, it will
look for a canonical metamodel class for each of the managed typed is knows about and if it finds
any it will inject the appropriate metamodel information into them, as outlined in
<citation><xref linkend="JPA2"/>, section 6.2.2, pg 200</citation>
</para>
</section>
</chapter>

View File

@ -1,136 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Inc or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Inc.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 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">
<chapter id="query_native">
<title>Native query</title>
<para>You may also express queries in the native SQL dialect of your
database. This is useful if you want to utilize database specific features
such as query hints or the CONNECT BY option in Oracle. It also provides a
clean migration path from a direct SQL/JDBC based application to Hibernate.
Note that Hibernate allows you to specify handwritten SQL (including stored
procedures) for all create, update, delete, and load operations (please
refer to the reference guide for more information.)</para>
<sect1>
<title>Expressing the resultset</title>
<para>To use a SQL query, you need to describe the SQL resultset, this
description will help the <literal>EntityManager</literal> to map your
columns onto entity properties. This is done using the
<literal>@SqlResultSetMapping</literal> annotation. Each
<literal>@SqlResultSetMapping </literal>has a name which is used when
creating a SQL query on <literal>EntityManager</literal>.</para>
<programlisting role="JAVA" language="JAVA">@SqlResultSetMapping(name="GetNightAndArea", entities={
@EntityResult(name="org.hibernate.test.annotations.query.Night", fields = {
@FieldResult(name="id", column="nid"),
@FieldResult(name="duration", column="night_duration"),
@FieldResult(name="date", column="night_date"),
@FieldResult(name="area", column="area_id")
}),
@EntityResult(name="org.hibernate.test.annotations.query.Area", fields = {
@FieldResult(name="id", column="aid"),
@FieldResult(name="name", column="name")
})
}
)
//or
@SqlResultSetMapping(name="defaultSpaceShip", entities=@EntityResult(name="org.hibernate.test.annotations.query.SpaceShip"))</programlisting>
<para>You can also define scalar results and even mix entity results and
scalar results</para>
<programlisting role="JAVA" language="JAVA">@SqlResultSetMapping(name="ScalarAndEntities",
entities={
@EntityResult(name="org.hibernate.test.annotations.query.Night", fields = {
@FieldResult(name="id", column="nid"),
@FieldResult(name="duration", column="night_duration"),
@FieldResult(name="date", column="night_date"),
@FieldResult(name="area", column="area_id")
}),
@EntityResult(name="org.hibernate.test.annotations.query.Area", fields = {
@FieldResult(name="id", column="aid"),
@FieldResult(name="name", column="name")
})
},
columns={
@ColumnResult(name="durationInSec")
}
)</programlisting>
<para>The SQL query will then have to return a column alias
<literal>durationInSec</literal>.</para>
<para>Please refer to the Hibernate Annotations reference guide for more
information about <literal>@SqlResultSetMapping.</literal></para>
</sect1>
<sect1>
<title>Using native SQL Queries</title>
<para>TODO: This sounds like a dupe...</para>
<para>Now that the result set is described, we are capable of executing
the native SQL query. <literal>EntityManager</literal> provides all the
needed APIs. The first method is to use a SQL resultset name to do the
binding, the second one uses the entity default mapping (the column
returned has to have the same names as the one used in the mapping). A
third one (not yet supported by Hibernate entity manager), returns pure
scalar results.</para>
<programlisting role="JAVA" language="JAVA">String sqlQuery = "select night.id nid, night.night_duration, night.night_date, area.id aid, "
+ "night.area_id, area.name from Night night, Area area where night.area_id = area.id "
+ "and night.night_duration &gt;= ?";
Query q = entityManager.createNativeQuery(sqlQuery, "GetNightAndArea");
q.setParameter( 1, expectedDuration );
q.getResultList();</programlisting>
<para>This native query returns nights and area based on the
<literal>GetNightAndArea</literal> result set.</para>
<programlisting role="JAVA" language="JAVA">String sqlQuery = "select * from tbl_spaceship where owner = ?";
Query q = entityManager.createNativeQuery(sqlQuery, SpaceShip.class);
q.setParameter( 1, "Han" );
q.getResultList();</programlisting>
<para>The second version is useful when your SQL query returns one entity
reusing the same columns as the ones mapped in metadata.</para>
</sect1>
<sect1>
<title>Named queries</title>
<para>Native named queries share the same calling API than JP-QL named
queries. Your code doesn't need to know the difference between the two.
This is very useful for migration from SQL to JP-QL:</para>
<programlisting role="JAVA" language="JAVA">Query q = entityManager.createNamedQuery("getSeasonByNativeQuery");
q.setParameter( 1, name );
Season season = (Season) q.getSingleResult();</programlisting>
</sect1>
</chapter>