|
Hibernate example source code file (query_criteria.xml)
This example Hibernate source code file (query_criteria.xml) is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.
The Hibernate query_criteria.xml source code
<?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
<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 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
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
instance by calling the <methodname>getCriteriaBuilder method
of the
<interfacename>javax.persistence.EntityManagerFactory
<programlisting role="JAVA" language="JAVA">CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder();
<para>The next step is to obtain a
<interfacename>javax.persistence.criteria.CriteriaQuery. You
do this by one of the 3 methods on
<interfacename>javax.persistence.criteria.CriteriaBuilder
for this purpose.</para>
<programlisting role="JAVA" language="JAVA">CriteriaQuery<T> createQuery(Class<T>)
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Tuple> createTupleQuery()
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Object> createQuery()
<para>Each serves a different purpose depending on the expected type of the
query results.</para>
<note>
<para>Chapter 6 Criteria API of
the <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
<programlisting role="JAVA" language="JAVA">CriteriaQuery<T> createQuery(Class<T>)
<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
<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
<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 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>personCriteria.select( personRoot )
here is completely unneeded in this specific case because of the
fact that <emphasis>personRoot 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>Person_.eyeColor 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
<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
<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 as the type of the
<emphasis>Person#age attribute is
<classname>java.lang.Integer.
</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. We might have
multiple references to the Person entity in the query so we need
to identify (aka qualify) which <emphasis>Person#age we
mean.</para>
</callout>
</calloutlist>
</example>
<example id="ex-criteria-typedquery-expression">
<title>Selecting an expression
<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
used to obtain a <emphasis>MAX expression. These
expression building methods return
<interfacename>javax.persistence.criteria.Expression
instances typed according to various rules. The rule for a
<emphasis>MAX 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
<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
<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 array
method of the
<interfacename>javax.persistence.criteria.CriteriaBuilder
which explicitly combines individual selections into a
<interfacename>javax.persistence.criteria.CompoundSelection.
</callout>
</calloutlist>
</example>
<example id="ex-criteria-typedquery-array2">
<title>Selecting an array (2)
<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 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[].
</callout>
</calloutlist>
</example>
</section>
<section id="querycriteria-typedquery-construct">
<title>Selecting a wrapper
<para>Another alternative to instead declare a class
that holds these values and instead return that.</para>
<example id="ex-criteria-typedquery-construct">
<title>Selecting an wrapper
<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 objects, we use
<emphasis>PersonWrapper 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
method, <methodname>construct, which is used to
builder a wrapper expression. Basically for every row in the
result we are saying we would like a
<emphasis>PersonWrapper 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
<para>A better approach to contract.
<example id="ex-criteria-typedquery-tuple">
<title>Selecting a tuple
<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>javax.persistence.criteria.CriteriaQuery
building method, <methodname>createTupleQuery. 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
contract.</para>
</callout>
<callout arearefs="ex.criteria.typedquery.tuple.2">
<para>Again we see the use of the
<methodname>multiselect method, just like in
was defined as
<interfacename>javax.persistence.Tuple 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 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
<para>The javax.persistence.Tuple
contract provides 3 basic forms of access to the underlying
elements:</para>
<variablelist>
<varlistentry>
<term>typed
<listitem>
<programlisting role="JAVA" language="JAVA"><X> X get(TupleElement<X> tupleElement)
<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 ) and
<emphasis>tuple.get( agePath ) calls. Just about
everything is a
<interfacename>javax.persistence.TupleElement.
</listitem>
</varlistentry>
<varlistentry>
<term>positional
<listitem>
<programlisting role="JAVA" language="JAVA">Object get(int i)
<programlisting role="JAVA" language="JAVA"><X> X get(int i, Class<X> type)
<para>Very similar to what we saw in and tuple.get( 1
)</emphasis> calls.
</listitem>
</varlistentry>
<varlistentry>
<term>aliased
<listitem>
<programlisting role="JAVA" language="JAVA">Object get(String alias)
<programlisting role="JAVA" language="JAVA"><X> X get(String alias, Class<X> type)
<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" ) and/or
<emphasis>agePath.alias( "age" ) 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
<blockquote>
<attribution>, section 6.5.2 Query
Roots, pg 262</citation>
<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
interface.</para>
</note>
<section id="querycriteria-from-root">
<title>Roots
<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 methods on
<interfacename>javax.persistence.criteria.CriteriaQuery:
<programlisting role="JAVA" language="JAVA"><X> Root<X> from(Class<X>)
<programlisting role="JAVA" language="JAVA"><X> Root<X> from(EntityType<X>)
<example>
<title>Adding a root
<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
<para>Joins allow navigation from other
<interfacename>javax.persistence.criteria.From to either
association or embedded attributes. Joins are created by the numerous
overloaded <methodname>join methods of the
<interfacename>javax.persistence.criteria.From
interface:</para>
<example id="criteria-join-singular">
<title>Example with Embedded and ManyToOne
<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
<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
<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 methods of the
<interfacename>javax.persistence.criteria.From
interface:</para>
<example id="criteria-fetch-singular">
<title>Example with Embedded and ManyToOne
<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 we needed a
<interfacename>javax.persistence.criteria.Fetch for
its parent path.</para>
</note>
<example id="criteria-fetch-plural">
<title>Example with Collections
<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
<note>
<para>Roots, joins and fetches are themselves paths as well.
</note>
</section>
<section id="querycriteria-param">
<title>Using parameters
<example id="ex-querycriteria-param">
<title>Using parameters
<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 parameter method of
<interfacename>javax.persistence.criteria.CriteriaBuilder
to obtain a parameter reference.</para>
</callout>
<callout arearefs="ex.criteria.param.2">
<para>Use the parameter reference in the criteria query.
</callout>
<callout arearefs="ex.criteria.param.3">
<para>Use the parameter reference to bind the parameter value to
the
<interfacename>javax.persistence.TypedQuery
</callout>
</calloutlist>
</programlistingco>
</example>
</section>
</chapter>
Other Hibernate examples (source code examples)
Here is a short list of links related to this Hibernate query_criteria.xml source code file:
|