HHH-10022 - Continue documentation TLC (part 2)
This commit is contained in:
parent
8dc14436af
commit
85dbceac20
|
@ -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>
|
||||||
|
|
|
@ -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><one-to-many/></literal>
|
||||||
|
or <literal><many-to-many/></literal>) or components
|
||||||
|
(<literal><composite-element/></literal> ),
|
||||||
|
and the second is if the collection contains scalar values
|
||||||
|
(<literal><element/></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
|
||||||
|
"elements". For an indexed collection, we can also reference the index property using
|
||||||
|
the special property "indices".
|
||||||
|
</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><natural-id></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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<T> CriteriaQuery<T> createQuery(Class<T> resultClass);
|
||||||
|
CriteriaQuery<Tuple> createTupleQuery();
|
||||||
|
CriteriaQuery<Object> createQuery();
|
|
@ -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 );
|
|
@ -0,0 +1,4 @@
|
||||||
|
CriteriaQuery<Person> 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 );
|
|
@ -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 );
|
|
@ -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 );
|
|
@ -0,0 +1,3 @@
|
||||||
|
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||||
|
// create and add the root
|
||||||
|
person.from( Person.class );
|
|
@ -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 ) );
|
|
@ -0,0 +1,3 @@
|
||||||
|
<X> Root<X> from(Class<X>);
|
||||||
|
|
||||||
|
<X> Root<X> from(EntityType<X>)
|
|
@ -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();
|
|
@ -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 ) {
|
||||||
|
...
|
||||||
|
}
|
|
@ -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];
|
||||||
|
...
|
||||||
|
}
|
|
@ -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];
|
||||||
|
...
|
||||||
|
}
|
|
@ -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 ) {
|
||||||
|
...
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
...
|
||||||
|
}
|
|
@ -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
|
@ -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?)
|
||||||
|
|
Loading…
Reference in New Issue