HHH-6082 - Incorporate EntityManager documentation into main dev guide
This commit is contained in:
parent
591364409e
commit
30deb20ff1
|
@ -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" />
|
||||
|
|
|
@ -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>
|
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
|
@ -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>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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) < 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 <METHOD>(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"><?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<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"
|
||||
>
|
||||
<persistence-unit-metadata>
|
||||
<persistence-unit-defaults>
|
||||
<entity-listeners>
|
||||
<entity-listener class="org.hibernate.ejb.test.pack.defaultpar.IncrementListener">
|
||||
<pre-persist method-name="increment"/>
|
||||
</entity-listener>
|
||||
</entity-listeners>
|
||||
</persistence-unit-defaults>
|
||||
</persistence-unit-metadata>
|
||||
<package>org.hibernate.ejb.test.pack.defaultpar</package>
|
||||
<entity class="ApplicationServer">
|
||||
<entity-listeners>
|
||||
<entity-listener class="OtherIncrementListener">
|
||||
<pre-persist method-name="increment"/>
|
||||
</entity-listener>
|
||||
</entity-listeners>
|
||||
|
||||
|
||||
<pre-persist method-name="calculate"/>
|
||||
</entity>
|
||||
</entity-mappings></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
|
||||
<exclude-default-listeners/>).</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -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<T> createQuery(Class<T>)</programlisting>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Tuple> createTupleQuery()</programlisting>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Object> 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<T> createQuery(Class<T>)</programlisting>
|
||||
|
||||
<para>The type of the criteria query (aka the <T>) 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<Person> criteria = builder.createQuery( Person.class );
|
||||
Root<Person> personRoot = criteria.from( Person.class );
|
||||
criteria.select( personRoot );
|
||||
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
|
||||
List<Person> 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<Integer> criteria = builder.createQuery( Integer.class );
|
||||
Root<Person> personRoot = criteria.from( Person.class );
|
||||
criteria.select( personRoot.get( Person_.age ) );
|
||||
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
|
||||
List<Integer> 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<Integer> criteria = builder.createQuery( Integer.class );
|
||||
Root<Person> 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<Object[]> criteria = builder.createQuery( Object[].class );
|
||||
Root<Person> personRoot = criteria.from( Person.class );
|
||||
Path<Long> idPath = personRoot.get( Person_.id );
|
||||
Path<Integer> agePath = personRoot.get( Person_.age );
|
||||
criteria.select( builder.array( idPath, agePath ) );
|
||||
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
|
||||
List<Object[]> 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<Object[]> criteria = builder.createQuery( Object[].class );
|
||||
Root<Person> personRoot = criteria.from( Person.class );
|
||||
Path<Long> idPath = personRoot.get( Person_.id );
|
||||
Path<Integer> agePath = personRoot.get( Person_.age );
|
||||
criteria.multiselect( idPath, agePath );
|
||||
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
|
||||
List<Object[]> 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<PersonWrapper> criteria = builder.createQuery( PersonWrapper.class );
|
||||
Root<Person> 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<PersonWrapper> 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<Tuple> criteria = builder.createTupleQuery();
|
||||
Root<Person> personRoot = criteria.from( Person.class );
|
||||
Path<Long> idPath = personRoot.get( Person_.id );
|
||||
Path<Integer> agePath = personRoot.get( Person_.age );
|
||||
criteria.multiselect( idPath, agePath );
|
||||
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
|
||||
List<Tuple> 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"><X> X get(TupleElement<X> 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"><X> X get(int i, Class<X> 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"><X> X get(String alias, Class<X> 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"><X> Root<X> from(Class<X>)</programlisting>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA"><X> Root<X> from(EntityType<X>)</programlisting>
|
||||
|
||||
<example>
|
||||
<title>Adding a root</title>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Person> 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<Person> men = query.from( Person.class );
|
||||
Root<Person> 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<Person> personCriteria = builder.createQuery( Person.class );
|
||||
Root<Person> personRoot = person.from( Person.class );
|
||||
// Person.address is an embedded attribute
|
||||
Join<Person,Address> personAddress = personRoot.join( Person_.address );
|
||||
// Address.country is a ManyToOne
|
||||
Join<Address,Country> addressCountry = personAddress.join( Address_.country );
|
||||
...</programlisting>
|
||||
</example>
|
||||
|
||||
<example id="criteria-join-plural">
|
||||
<title>Example with Collections</title>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
Root<Person> personRoot = person.from( Person.class );
|
||||
Join<Person,Order> orders = personRoot.join( Person_.orders );
|
||||
Join<Order,LineItem> 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<Person> personCriteria = builder.createQuery( Person.class );
|
||||
Root<Person> personRoot = person.from( Person.class );
|
||||
// Person.address is an embedded attribute
|
||||
Join<Person,Address> personAddress = personRoot.fetch( Person_.address );
|
||||
// Address.country is a ManyToOne
|
||||
Join<Address,Country> 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<Person> personCriteria = builder.createQuery( Person.class );
|
||||
Root<Person> personRoot = person.from( Person.class );
|
||||
Join<Person,Order> orders = personRoot.fetch( Person_.orders );
|
||||
Join<Order,LineItem> 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<Person> criteria = build.createQuery( Person.class );
|
||||
Root<Person> personRoot = criteria.from( Person.class );
|
||||
criteria.select( personRoot );
|
||||
ParameterExpression<String> eyeColorParam = builder.parameter( String.class );
|
||||
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), eyeColorParam ) );
|
||||
TypedQuery<Person> query = em.createQuery( criteria );
|
||||
query.setParameter( eyeColorParam, "brown" );
|
||||
List<Person> 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>
|
|
@ -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><any></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>=, >=, <=, <>,
|
||||
!=, 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 > 0</programlisting>
|
||||
|
||||
<programlisting>select cat from Cat cat where size(cat.kittens) > 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) > current date</programlisting>
|
||||
|
||||
<programlisting>select order from Order order where maxindex(order.items) > 100</programlisting>
|
||||
|
||||
<programlisting>select order from Order order where minelement(order.items) > 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 > 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) < 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) > 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 > (
|
||||
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 < sysdate
|
||||
and catalog.effectiveDate >= all (
|
||||
select cat.effectiveDate
|
||||
from Catalog as cat
|
||||
where cat.effectiveDate < sysdate
|
||||
)
|
||||
group by order
|
||||
having sum(price.amount) > :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) > :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 <> PaymentStatus.AWAITING_APPROVAL
|
||||
or (
|
||||
statusChange.timeStamp = (
|
||||
select max(change.timeStamp)
|
||||
from PaymentStatusChange change
|
||||
where change.payment = payment
|
||||
)
|
||||
and statusChange.user <> :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 <> PaymentStatus.AWAITING_APPROVAL
|
||||
or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :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 & 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 & 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) >= 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) >= 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>
|
|
@ -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 && 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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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 >= ?";
|
||||
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>
|
Loading…
Reference in New Issue