HHH-10022 - Continue documentation TLC (part 2)

This commit is contained in:
Steve Ebersole 2015-08-06 14:59:25 -05:00
parent 8dc14436af
commit 85dbceac20
22 changed files with 2245 additions and 13 deletions

View File

@ -58,15 +58,18 @@
<xi:include href="chapters/events/Events.xml" /> <xi:include href="chapters/events/Events.xml" />
<!-- <!--
<xi:include href="chapters/query_ql/HQL_JPQL.xml" /> <xi:include href="chapters/query_ql/HQL_JPQL.xml" />
<xi:include href="chapters/query_criteria/Criteria.xml" />
<xi:include href="chapters/query_native/Native_SQL.xml" />
--> -->
<xi:include href="chapters/query-criteria/Criteria.xml" />
<xi:include href="chapters/query-native/Native.xml" />
<xi:include href="chapters/multitenancy/Multi_Tenancy.xml" /> <xi:include href="chapters/multitenancy/Multi_Tenancy.xml" />
<xi:include href="chapters/osgi/OSGi.xml" /> <xi:include href="chapters/osgi/OSGi.xml" />
<xi:include href="chapters/envers/Envers.xml" /> <xi:include href="chapters/envers/Envers.xml" />
<xi:include href="chapters/portability/Portability.xml" /> <xi:include href="chapters/portability/Portability.xml" />
<xi:include href="appendices/Appendix_LegacyBootstrap.xml" /> <xi:include href="appendices/Legacy_Bootstrap.xml" />
<xi:include href="appendices/Legacy_Criteria.xml" />
<xi:include href="Bibliography.xml" /> <xi:include href="Bibliography.xml" />
</book> </book>

View File

@ -0,0 +1,549 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<appendix xml:id="appendix-legacy-criteria" xmlns="http://docbook.org/ns/docbook">
<info>
<title>Legacy Hibernate Criteria Queries</title>
</info>
<note>
<para>
This appendix covers the legacy Hibernate <interfacename>org.hibernate.Criteria</interfacename> API, which
should be considered deprecated. New development should focus on the JPA
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename> API. Eventually,
Hibernate-specific criteria features will be ported as extensions to the JPA
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. For details on the JPA APIs, see
<xref linkend="query-criteria"/>.
</para>
<para>
This information is copied as-is from the older Hibernate documentation.
</para>
</note>
<para>
Hibernate features an intuitive, extensible criteria query API.
</para>
<section xml:id="querycriteria-creating">
<title>Creating a <literal>Criteria</literal> instance</title>
<para>
The interface <literal>org.hibernate.Criteria</literal> represents a query against
a particular persistent class. The <literal>Session</literal> is a factory for
<literal>Criteria</literal> instances.
</para>
<programlisting role="JAVA"><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();]]></programlisting>
</section>
<section xml:id="querycriteria-narrowing">
<title>Narrowing the result set</title>
<para>
An individual query criterion is an instance of the interface
<literal>org.hibernate.criterion.Criterion</literal>. The class
<literal>org.hibernate.criterion.Restrictions</literal> defines
factory methods for obtaining certain built-in
<literal>Criterion</literal> types.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();]]></programlisting>
<para>
Restrictions can be grouped logically.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.or(
Restrictions.eq( "age", new Integer(0) ),
Restrictions.isNull("age")
) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
.add( Restrictions.disjunction()
.add( Restrictions.isNull("age") )
.add( Restrictions.eq("age", new Integer(0) ) )
.add( Restrictions.eq("age", new Integer(1) ) )
.add( Restrictions.eq("age", new Integer(2) ) )
) )
.list();]]></programlisting>
<para>
There are a range of built-in criterion types (<literal>Restrictions</literal>
subclasses). One of the most useful allows you to specify SQL directly.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
.list();]]></programlisting>
<para>
The <literal>{alias}</literal> placeholder will be replaced by the row alias
of the queried entity.
</para>
<para>
You can also obtain a criterion from a
<literal>Property</literal> instance. You can create a <literal>Property</literal>
by calling <literal>Property.forName()</literal>:
</para>
<programlisting role="JAVA"><![CDATA[
Property age = Property.forName("age");
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.disjunction()
.add( age.isNull() )
.add( age.eq( new Integer(0) ) )
.add( age.eq( new Integer(1) ) )
.add( age.eq( new Integer(2) ) )
) )
.add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
.list();]]></programlisting>
</section>
<section xml:id="querycriteria-ordering">
<title>Ordering the results</title>
<para>
You can order the results using <literal>org.hibernate.criterion.Order</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name").nulls(NullPrecedence.LAST) )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Property.forName("name").like("F%") )
.addOrder( Property.forName("name").asc() )
.addOrder( Property.forName("age").desc() )
.setMaxResults(50)
.list();]]></programlisting>
</section>
<section xml:id="querycriteria-associations">
<title>Associations</title>
<para>
By navigating
associations using <literal>createCriteria()</literal> you can specify constraints upon related entities:
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%") )
.createCriteria("kittens")
.add( Restrictions.like("name", "F%") )
.list();]]></programlisting>
<para>
The second <literal>createCriteria()</literal> returns a new
instance of <literal>Criteria</literal> that refers to the elements of
the <literal>kittens</literal> collection.
</para>
<para>
There is also an alternate form that is useful in certain circumstances:
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.createAlias("kittens", "kt")
.createAlias("mate", "mt")
.add( Restrictions.eqProperty("kt.name", "mt.name") )
.list();]]></programlisting>
<para>
(<literal>createAlias()</literal> does not create a new instance of
<literal>Criteria</literal>.)
</para>
<para>
The kittens collections held by the <literal>Cat</literal> instances
returned by the previous two queries are <emphasis>not</emphasis> pre-filtered
by the criteria. If you want to retrieve just the kittens that match the
criteria, you must use a <literal>ResultTransformer</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.createCriteria("kittens", "kt")
.add( Restrictions.eq("name", "F%") )
.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
.list();
Iterator iter = cats.iterator();
while ( iter.hasNext() ) {
Map map = (Map) iter.next();
Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
Cat kitten = (Cat) map.get("kt");
}]]></programlisting>
<para>
Additionally you may manipulate the result set using a left outer join:
</para>
<programlisting><![CDATA[
List cats = session.createCriteria( Cat.class )
.createAlias("mate", "mt", Criteria.LEFT_JOIN, Restrictions.like("mt.name", "good%") )
.addOrder(Order.asc("mt.age"))
.list();
]]></programlisting>
<para>
This will return all of the <literal>Cat</literal>s with a mate whose name starts with "good"
ordered by their mate's age, and all cats who do not have a mate.
This is useful when there is a need to order or limit in the database
prior to returning complex/large result sets, and removes many instances where
multiple queries would have to be performed and the results unioned
by java in memory.
</para>
<para>
Without this feature, first all of the cats without a mate would need to be loaded in one query.
</para>
<para>
A second query would need to retreive the cats with mates who's name started with "good" sorted by the mates age.
</para>
<para>
Thirdly, in memory; the lists would need to be joined manually.
</para>
</section>
<section xml:id="querycriteria-dynamicfetching">
<title>Dynamic association fetching</title>
<para>
You can specify association fetching semantics at runtime using
<literal>setFetchMode()</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.setFetchMode("mate", FetchMode.EAGER)
.setFetchMode("kittens", FetchMode.EAGER)
.list();]]></programlisting>
<para>
This query will fetch both <literal>mate</literal> and <literal>kittens</literal>
by outer join.
</para>
</section>
<section xml:id="querycriteria-components" revision="2">
<title>Components</title>
<para>
To add a restriction against a property of an embedded component, the component property
name should be prepended to the property name when creating the <literal>Restriction</literal>.
The criteria object should be created on the owning entity, and cannot be created on the component
itself. For example, suppose the <literal>Cat</literal> has a component property <literal>fullName</literal>
with sub-properties <literal>firstName</literal> and <literal>lastName</literal>:
</para>
<programlisting><![CDATA[
List cats = session.createCriteria(Cat.class)
.add(Restrictions.eq("fullName.lastName", "Cattington"))
.list();]]>
</programlisting>
<para>
Note: this does not apply when querying collections of components, for that see below
<xref linkend="querycriteria-collections"/>
</para>
</section>
<section xml:id="querycriteria-collections" revision="1">
<title>Collections</title>
<para>
When using criteria against collections, there are two distinct cases. One is if
the collection contains entities (eg. <literal>&lt;one-to-many/&gt;</literal>
or <literal>&lt;many-to-many/&gt;</literal>) or components
(<literal>&lt;composite-element/&gt;</literal> ),
and the second is if the collection contains scalar values
(<literal>&lt;element/&gt;</literal>).
In the first case, the syntax is as given above in the section
<xref linkend="querycriteria-associations"/> where we restrict the <literal>kittens</literal>
collection. Essentially we create a <literal>Criteria</literal> object against the collection
property and restrict the entity or component properties using that instance.
</para>
<para>
For queryng a collection of basic values, we still create the <literal>Criteria</literal>
object against the collection, but to reference the value, we use the special property
&quot;elements&quot;. For an indexed collection, we can also reference the index property using
the special property &quot;indices&quot;.
</para>
<programlisting><![CDATA[
List cats = session.createCriteria(Cat.class)
.createCriteria("nickNames")
.add(Restrictions.eq("elements", "BadBoy"))
.list();]]>
</programlisting>
</section>
<section xml:id="querycriteria-examples">
<title>Example queries</title>
<para>
The class <literal>org.hibernate.criterion.Example</literal> allows
you to construct a query criterion from a given instance.
</para>
<programlisting role="JAVA"><![CDATA[Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.list();]]></programlisting>
<para>
Version properties, identifiers and associations are ignored. By default,
null valued properties are excluded.
</para>
<para>
You can adjust how the <literal>Example</literal> is applied.
</para>
<programlisting role="JAVA"><![CDATA[Example example = Example.create(cat)
.excludeZeroes() //exclude zero valued properties
.excludeProperty("color") //exclude the property named "color"
.ignoreCase() //perform case insensitive string comparisons
.enableLike(); //use like for string comparisons
List results = session.createCriteria(Cat.class)
.add(example)
.list();]]></programlisting>
<para>
You can even use examples to place criteria upon associated objects.
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.createCriteria("mate")
.add( Example.create( cat.getMate() ) )
.list();]]></programlisting>
</section>
<section xml:id="querycriteria-projection">
<title>Projections, aggregation and grouping</title>
<para>
The class <literal>org.hibernate.criterion.Projections</literal> is a
factory for <literal>Projection</literal> instances. You can apply a
projection to a query by calling <literal>setProjection()</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.rowCount() )
.add( Restrictions.eq("color", Color.BLACK) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount() )
.add( Projections.avg("weight") )
.add( Projections.max("weight") )
.add( Projections.groupProperty("color") )
)
.list();]]></programlisting>
<para>
There is no explicit "group by" necessary in a criteria query. Certain
projection types are defined to be <emphasis>grouping projections</emphasis>,
which also appear in the SQL <literal>group by</literal> clause.
</para>
<para>
An alias can be assigned to a projection so that the projected value
can be referred to in restrictions or orderings. Here are two different ways to
do this:
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
.addOrder( Order.asc("colr") )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.groupProperty("color").as("colr") )
.addOrder( Order.asc("colr") )
.list();]]></programlisting>
<para>
The <literal>alias()</literal> and <literal>as()</literal> methods simply wrap a
projection instance in another, aliased, instance of <literal>Projection</literal>.
As a shortcut, you can assign an alias when you add the projection to a
projection list:
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount(), "catCountByColor" )
.add( Projections.avg("weight"), "avgWeight" )
.add( Projections.max("weight"), "maxWeight" )
.add( Projections.groupProperty("color"), "color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder( Order.desc("avgWeight") )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
.createAlias("kittens", "kit")
.setProjection( Projections.projectionList()
.add( Projections.property("cat.name"), "catName" )
.add( Projections.property("kit.name"), "kitName" )
)
.addOrder( Order.asc("catName") )
.addOrder( Order.asc("kitName") )
.list();]]></programlisting>
<para>
You can also use <literal>Property.forName()</literal> to express projections:
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Property.forName("name") )
.add( Property.forName("color").eq(Color.BLACK) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount().as("catCountByColor") )
.add( Property.forName("weight").avg().as("avgWeight") )
.add( Property.forName("weight").max().as("maxWeight") )
.add( Property.forName("color").group().as("color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder( Order.desc("avgWeight") )
.list();]]></programlisting>
</section>
<section xml:id="querycriteria-detachedqueries">
<title>Detached queries and subqueries</title>
<para>
The <literal>DetachedCriteria</literal> class allows you to create a query outside the scope
of a session and then execute it using an arbitrary <literal>Session</literal>.
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
.add( Property.forName("sex").eq('F') );
Session session = ....;
Transaction txn = session.beginTransaction();
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();]]></programlisting>
<para>
A <literal>DetachedCriteria</literal> can also be used to express a subquery. Criterion
instances involving subqueries can be obtained via <literal>Subqueries</literal> or
<literal>Property</literal>.
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
.add( Property.forName("weight").gt(avgWeight) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight") );
session.createCriteria(Cat.class)
.add( Subqueries.geAll("weight", weights) )
.list();]]></programlisting>
<para>
Correlated subqueries are also possible:
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
.setProjection( Property.forName("weight").avg() )
.add( Property.forName("cat2.sex").eqProperty("cat.sex") );
session.createCriteria(Cat.class, "cat")
.add( Property.forName("weight").gt(avgWeightForSex) )
.list();]]></programlisting>
<para>
Example of multi-column restriction based on a subquery:
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria sizeQuery = DetachedCriteria.forClass( Man.class )
.setProjection( Projections.projectionList().add( Projections.property( "weight" ) )
.add( Projections.property( "height" ) ) )
.add( Restrictions.eq( "name", "John" ) );
session.createCriteria( Woman.class )
.add( Subqueries.propertiesEq( new String[] { "weight", "height" }, sizeQuery ) )
.list();]]></programlisting>
</section>
<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
user objects - similar to setResultClass in JDO2. General use of ResultTransformer
could also be explained. -->
<section xml:id="query-criteria-naturalid">
<title>Queries by natural identifier</title>
<para>
For most queries, including criteria queries, the query cache is not efficient
because query cache invalidation occurs too frequently. However, there is a special
kind of query where you can optimize the cache invalidation algorithm: lookups by a
constant natural key. In some applications, this kind of query occurs frequently.
The criteria API provides special provision for this use case.
</para>
<para>
First, map the natural key of your entity using
<literal>&lt;natural-id&gt;</literal> and enable use of the second-level cache.
</para>
<programlisting role="XML"><![CDATA[<class name="User">
<cache usage="read-write"/>
<id name="id">
<generator class="increment"/>
</id>
<natural-id>
<property name="name"/>
<property name="org"/>
</natural-id>
<property name="password"/>
</class>]]></programlisting>
<para>
This functionality is not intended for use with entities with
<emphasis>mutable</emphasis> natural keys.
</para>
<para>
Once you have enabled the Hibernate query cache,
the <literal>Restrictions.naturalId()</literal> allows you to make use of
the more efficient cache algorithm.
</para>
<programlisting role="JAVA"><![CDATA[session.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
).setCacheable(true)
.uniqueResult();]]></programlisting>
</section>
</appendix>

View File

@ -11,6 +11,10 @@
xmlns:xi="http://www.w3.org/2001/XInclude"> xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Fetching</title> <title>Fetching</title>
<!-- todo : document special fetching considerations such as batch fetching, subselect fetching and extra laziness -->
<!-- todo : document "dynamic fetching via JPA entity graphs" -->
<!-- todo : list out the default fetching strategies by association type (JPA); recommend all lazy; allow users to override the to-one default (add jira) -->
<para> <para>
Fetching, essentially, is the process of grabbing data from the database and making it available to the Fetching, essentially, is the process of grabbing data from the database and making it available to the
application. Tuning how an application does fetching is one of the biggest factors in determining how an application. Tuning how an application does fetching is one of the biggest factors in determining how an
@ -76,6 +80,11 @@
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</listitem> </listitem>
<listitem>
<para>
Starting in Hibernate 4.2 (JPA 2.1) you can also use JPA EntityGraphs.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</para> </para>
@ -143,7 +152,7 @@
The Hibernate recommendation is to statically mark all associations lazy and to use dynamic fetching The Hibernate recommendation is to statically mark all associations lazy and to use dynamic fetching
strategies for eagerness. This is unfortunately at odds with the JPA specification which defines that strategies for eagerness. This is unfortunately at odds with the JPA specification which defines that
all one-to-one and many-to-one associations should be eagerly fetched by default. Hibernate, as a JPA all one-to-one and many-to-one associations should be eagerly fetched by default. Hibernate, as a JPA
provider honors that default. provider, honors that default.
</para> </para>
</important> </important>
@ -195,8 +204,8 @@
<para> <para>
In this example we have an Employee and their Projects loaded in a single query shown both as an HQL In this example we have an Employee and their Projects loaded in a single query shown both as an HQL
query and a JPA Criteria query. In both cases, this resolves to exactly one database query to get query and a JPA Criteria query. In both cases, this resolves to exactly one database query to get all
all that information. that information.
</para> </para>
</section> </section>
@ -226,7 +235,4 @@
</section> </section>
</section> </section>
<!-- todo : document special fetching considerations such as batch fetching, subselect fetching and extra laziness -->
<!-- todo : document "dynamic fetching via JPA entity graphs" -->
</chapter> </chapter>

View File

@ -0,0 +1,413 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Criteria</title>
<para>
Criteria queries offer a type-safe alternative to HQL, JPQL and native-sql queries.
</para>
<important>
<para>
Hibernate offers an older, legacy <interfacename>org.hibernate.Criteria</interfacename> API which should be
considered deprecated. No feature development will target those APIs. Eventually, Hibernate-specific
criteria features will be ported as extensions to the JPA
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. For details on the
<interfacename>org.hibernate.Criteria</interfacename> API, see <xref linkend="appendix-legacy-criteria"/>.
</para>
<para>
This chapter will focus on the JPA APIs for declaring type-safe criteria queries.
</para>
</important>
<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 either
<interfacename>javax.persistence.EntityManagerFactory</interfacename> or
<interfacename>javax.persistence.EntityManager</interfacename>.
</para>
<para>
The next step is to obtain a <interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. This
is accomplished using one of the 3 methods on
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> for this purpose:
</para>
<programlisting role="JAVA"><xi:include href="extras/CriteriaBuilder_query_creation_snippet.java" parse="text"/></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 JPA Specification
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 xml:id="querycriteria-typedquery">
<title>Typed criteria queries</title>
<para>
The type of the criteria query (aka the <![CDATA[<T>]]>) indicates the expected types in the query
result. This might be an entity, an Integer, or any other object.
</para>
<section xml:id="querycriteria-typedquery-entity">
<title>Selecting an entity</title>
<para>
This is probably the most common form of query. The application wants to select entity instances.
</para>
<example xml:id="ex-criteria-typedquery-entity">
<title>Selecting the root entity</title>
<programlisting role="JAVA"><xi:include href="extras/select_root_entity_example.java" parse="text"/></programlisting>
</example>
<para>
The example uses <methodname>createQuery</methodname> passing in the <classname>Person</classname>
class reference as the results of the query will be Person objects.
</para>
<note>
<para>
The call to the <methodname>CriteriaQuery.select</methodname> method in this example is
unnecessary because <emphasis>personRoot</emphasis> will be the implied selection since we
have only a single query root. It was done here only for completeness of an example.
</para>
<para>
The <emphasis>Person_.eyeColor</emphasis> reference is an example of the static form of JPA
metamodel reference. We will use that form exclusively in this chapter. See
the documentation for the Hibernate JPA Metamodel Generator for additional details on
the JPA static metamodel.
</para>
</note>
</section>
<section xml:id="querycriteria-typedquery-expression">
<title>Selecting an expression</title>
<para>
The simplest form of selecting an expression is selecting a particular attribute from an entity.
But this expression might also represent an aggregation, a mathematical operation, etc.
</para>
<example xml:id="ex-criteria-typedquery-attribute">
<title>Selecting an attribute</title>
<programlisting role="JAVA"><xi:include href="extras/select_attribute_example.java" parse="text"/></programlisting>
</example>
<para>
In this example, the query is typed as <classname>java.lang.Integer</classname> because that
is the anticipated type of the results (the type of the <methodname>Person#age</methodname> attribute
is <classname>java.lang.Integer</classname>). Because a query might contain multiple references to
the Person entity, attribute references always need to be qualified. This is accomplished by the
<methodname>Root#get</methodname> method call.
</para>
</section>
<section xml: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" />. Or consider a wrapper query; see
<xref linkend="querycriteria-typedquery-construct"/> for details.
</para>
<example xml:id="ex-criteria-typedquery-array">
<title>Selecting an array</title>
<programlisting role="JAVA"><xi:include href="extras/select_multiple_values_array.java" parse="text"/></programlisting>
</example>
<para>
Technically this is classified as a typed query, but you can see from handling the results that
this is sort of misleading. Anyway, the expected result type here is an array.
</para>
<para>
The example then uses the <methodname>array</methodname> method of
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> which explicitly
combines individual selections into a
<interfacename>javax.persistence.criteria.CompoundSelection</interfacename>.
</para>
<example xml:id="ex-criteria-typedquery-array2">
<title>Selecting an array (2)</title>
<programlisting role="JAVA"><xi:include href="extras/select_multiple_values_array2.java" parse="text"/></programlisting>
</example>
<para>
Just as we saw in <xref linkend="ex-criteria-typedquery-array" /> we have a typed criteria
query returning an Object array. Both queries are functionally equivalent. This second example
uses the <methodname>multiselect</methodname> method which 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>
</section>
<section xml: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 <quote>wrap</quote> 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 xml:id="ex-criteria-typedquery-construct">
<title>Selecting an wrapper</title>
<programlisting role="JAVA"><xi:include href="extras/select_wrapper.java" parse="text"/></programlisting>
</example>
<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. Since we will be returning
<classname>PersonWrapper</classname> objects, we use <classname>PersonWrapper</classname> as the
type of our criteria query.
</para>
<para>
This example illustrates the use of the
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> method
<methodname>construct</methodname> which is used to build a wrapper expression. For every row in the
result we are saying we would like a <emphasis>PersonWrapper</emphasis> instantiated with
the remaining arguments by the matching constructor. This wrapper expression is then passed as
the select.
</para>
</section>
</section>
<section xml:id="querycriteria-tuple">
<title>Tuple criteria queries</title>
<para>
A better approach to <xref linkend="querycriteria-typedquery-multiselect" /> is to use either a
wrapper (which we just saw in <xref linkend="querycriteria-typedquery-construct" />) or using the
<interfacename>javax.persistence.Tuple</interfacename> contract.
</para>
<example xml:id="ex-criteria-typedquery-tuple">
<title>Selecting a tuple</title>
<programlisting role="JAVA"><xi:include href="extras/select_tuple.java" parse="text"/></programlisting>
</example>
<para>
This example illustrates accessing the query results through the
<interfacename>javax.persistence.Tuple</interfacename> interface. The example uses the explicit
<methodname>createTupleQuery</methodname> of
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>. An alternate approach
is to use <methodname>createQuery</methodname> passing <literal>Tuple.class</literal>.
</para>
<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>
<para>
The <interfacename>javax.persistence.Tuple</interfacename> contract provides 3 forms of access to
the underlying elements:
</para>
<variablelist>
<varlistentry>
<term>typed</term>
<listitem>
<para>
The <xref linkend="ex-criteria-typedquery-tuple"/> example illustrates this form of access
in the <literal>tuple.get( idPath )</literal> and <literal>tuple.get( agePath )</literal> calls.
This allows typed access to the underlying tuple values based on the
<interfacename>javax.persistence.TupleElement</interfacename> expressions used to build
the criteria.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>positional</term>
<listitem>
<para>
Allows access to the underlying tuple values based on the position. The simple
<emphasis>Object get(int position)</emphasis> form is very similar to the access
illustrated in <xref linkend="ex-criteria-typedquery-array" /> and
<xref linkend="ex-criteria-typedquery-array2" />. The
<emphasis><![CDATA[<X> X get(int position, Class<X> type]]></emphasis> form
allows typed positional access, but based on the explicitly supplied type which the tuple
value must be type-assignable to.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>aliased</term>
<listitem>
<para>
Allows access to the underlying tuple values based an (optionally) assigned alias. The
example query did not apply an alias. An alias would be applied via the
<methodname>alias</methodname> method on
<interfacename>javax.persistence.criteria.Selection</interfacename>. Just like
<literal>positional</literal> access, there is both a typed
(<emphasis>Object get(String alias)</emphasis>) and an untyped
(<emphasis><![CDATA[<X> X get(String alias, Class<X> type]]></emphasis> form.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="querycriteria-from">
<title>FROM clause</title>
<blockquote>
<attribution><citetitle>JPA Specification</citetitle>, section 6.5.2 Query Roots, pg 262</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 xml:id="querycriteria-from-root">
<title>Roots</title>
<para>
Roots define the basis from which all joins, paths and attributes are available in the query.
A root is always an entity type. 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"><xi:include href="extras/from_root_methods.java" parse="text"/></programlisting>
<example>
<title>Adding a root</title>
<programlisting role="JAVA"><xi:include href="extras/from_root_example.java" parse="text"/></programlisting>
</example>
<para>
Criteria queries may define multiple roots, the effect of which is to create a cartesian
product between the newly added root and the others. Here is an example matching all single
men and all single women:
</para>
<example>
<title>Adding multiple roots</title>
<programlisting role="JAVA"><xi:include href="extras/from_root_example_multiple.java" parse="text"/></programlisting>
</example>
</section>
<section xml: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 xml:id="criteria-join-singular">
<title>Example with Embedded and ManyToOne</title>
<programlisting role="JAVA"><xi:include href="extras/from_join_example_embedded_and_many2one.java" parse="text"/></programlisting>
</example>
<example xml:id="criteria-join-plural">
<title>Example with Collections</title>
<programlisting role="JAVA"><xi:include href="extras/from_join_example_plural.java" parse="text"/></programlisting>
</example>
</section>
<section xml:id="querycriteria-from-fetch">
<title>Fetches</title>
<para>
Just like in HQL and JPQL, criteria queries 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 xml:id="criteria-fetch-singular">
<title>Example with Embedded and ManyToOne</title>
<programlisting role="JAVA"><xi:include href="extras/from_fetch_example_embedded_and_many2one.java" parse="text"/></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 xml:id="criteria-fetch-plural">
<title>Example with Collections</title>
<programlisting role="JAVA"><xi:include href="extras/from_fetch_example_plural.java" parse="text"/></programlisting>
</example>
</section>
</section>
<section xml:id="querycriteria-path">
<title>Path expressions</title>
<note>
<para>
Roots, joins and fetches are themselves paths as well.
</para>
</note>
</section>
<section xml:id="querycriteria-param">
<title>Using parameters</title>
<example xml:id="ex-querycriteria-param">
<title>Using parameters</title>
<programlisting role="JAVA"><xi:include href="extras/parameter_example.java" parse="text"/></programlisting>
</example>
<para>
Use the <methodname>parameter</methodname> method of
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> to obtain a parameter
reference. Then use the parameter reference to bind the parameter value to the
<interfacename>javax.persistence.Query</interfacename>
</para>
</section>
</chapter>

View File

@ -0,0 +1,3 @@
<T> CriteriaQuery<T> createQuery(Class<T> resultClass);
CriteriaQuery<Tuple> createTupleQuery();
CriteriaQuery<Object> createQuery();

View File

@ -0,0 +1,6 @@
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
// Person.address is an embedded attribute
Fetch<Person,Address> personAddress = personRoot.fetch( Person_.address );
// Address.country is a ManyToOne
Fetch<Address,Country> addressCountry = personAddress.fetch( Address_.country );

View File

@ -0,0 +1,4 @@
CriteriaQuery&lt;Person&gt; personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
Fetch<Person,Order> orders = personRoot.fetch( Person_.orders );
Fetch<Order,LineItem> orderLines = orders.fetch( Order_.lineItems );

View File

@ -0,0 +1,6 @@
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 );

View File

@ -0,0 +1,4 @@
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 );

View File

@ -0,0 +1,3 @@
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
// create and add the root
person.from( Person.class );

View File

@ -0,0 +1,12 @@
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 ) );

View File

@ -0,0 +1,3 @@
<X> Root<X> from(Class<X>);
<X> Root<X> from(EntityType<X>)

View File

@ -0,0 +1,9 @@
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();

View File

@ -0,0 +1,9 @@
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 ) {
...
}

View File

@ -0,0 +1,13 @@
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];
...
}

View File

@ -0,0 +1,13 @@
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];
...
}

View File

@ -0,0 +1,9 @@
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 ) {
...
}

View File

@ -0,0 +1,13 @@
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 );
...
}

View File

@ -0,0 +1,27 @@
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 ) {
...
}

File diff suppressed because it is too large Load Diff

View File

@ -21,15 +21,16 @@ Covers reference topics targeting users.
* <strike>Database_Access</strike> * <strike>Database_Access</strike>
* <strike>Transactions</strike> * <strike>Transactions</strike>
* <strike>JNDI</strike> * <strike>JNDI</strike>
* Fetching (needs some work) * Fetching (needs some work) - document batch fetching, subselect fetching, extra laziness and EntityGraphs
* Flushing (to be written)
* Cascading (needs lots of work) * Cascading (needs lots of work)
* Locking (needs some work) * Locking (needs some work)
* Batching (needs lot of work - not started - open questions) * Batching (needs lot of work - not started - open questions)
* Caching (needs some work) * Caching (needs some work)
* Events (need some work) * Events (need some work)
* HQL_JPQL (needs lots of work) * Query - HQL/JPQL (needs lots of work)
* Criteria (needs lots of work) * <strike>Query - Criteria</strike>
* Native_Queries (needs lots of work) * <strike>Query - Native (copy from old)</strike>
* Multi_Tenancy (needs some work) * Multi_Tenancy (needs some work)
* OSGi (right place for this?) * OSGi (right place for this?)
* Envers (right place for this?) * Envers (right place for this?)