HHH-4933 finish documentation on JPA 2 and EntityManager, migrate to jHighlight
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18956 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
a284638d01
commit
3153fb385d
|
@ -70,6 +70,12 @@
|
|||
<surname>Ebersole</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Gavin</firstname>
|
||||
|
||||
<surname>King</surname>
|
||||
</author>
|
||||
|
||||
<!--TODO add translators like core did -->
|
||||
</authorgroup>
|
||||
</bookinfo>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
|
@ -22,8 +22,8 @@
|
|||
~ 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">
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter id="batch">
|
||||
<title>Batch processing</title>
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
Hibernate reference guide, however, EJB3 persistence differs
|
||||
slightly.</para>
|
||||
|
||||
<sect1 id="batch-direct">
|
||||
<section id="batch-direct">
|
||||
<title>Bulk update/delete</title>
|
||||
|
||||
<para>As already discussed, automatic and transparent object/relational
|
||||
|
@ -44,7 +44,7 @@
|
|||
directly in the database will not affect in-memory state. However,
|
||||
Hibernate provides methods for bulk SQL-style <literal>UPDATE</literal>
|
||||
and <literal>DELETE</literal> statement execution which are performed
|
||||
through EJB-QL (<xref linkend="queryhql" />).</para>
|
||||
through JP-QL (<xref linkend="queryhql" />).</para>
|
||||
|
||||
<para>The pseudo-syntax for <literal>UPDATE</literal> and
|
||||
<literal>DELETE</literal> statements is: <literal>( UPDATE | DELETE )
|
||||
|
@ -63,7 +63,7 @@
|
|||
|
||||
<listitem>
|
||||
<para>No joins (either implicit or explicit) can be specified in a
|
||||
bulk EJB-QL query. Sub-queries may be used in the where-clause.</para>
|
||||
bulk JP-QL query. Sub-queries may be used in the where-clause.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
|
@ -71,26 +71,26 @@
|
|||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>As an example, to execute an EJB-QL <literal>UPDATE</literal>, use
|
||||
<para>As an example, to execute an JP-QL <literal>UPDATE</literal>, use
|
||||
the <literal>Query.executeUpdate()</literal> method:</para>
|
||||
|
||||
<programlisting>EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
<programlisting role="JAVA" language="JAVA">EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
|
||||
String ejbqlUpdate = "update Customer set name = :newName where name = :oldName"
|
||||
int updatedEntities = entityManager.createQuery( ejbqlUpdate )
|
||||
String jpqlUpdate = "update Customer set name = :newName where name = :oldName"
|
||||
int updatedEntities = entityManager.createQuery( jpqlUpdate )
|
||||
.setParameter( "newName", newName )
|
||||
.setParameter( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
entityManager.getTransaction().commit();
|
||||
entityManager.close();</programlisting>
|
||||
|
||||
<para>To execute an EJB-QL <literal>DELETE</literal>, use the same
|
||||
<para>To execute an JP-QL <literal>DELETE</literal>, use the same
|
||||
<literal>Query.executeUpdate()</literal> method (the method is named for
|
||||
those familiar with JDBC's
|
||||
<literal>PreparedStatement.executeUpdate()</literal>):</para>
|
||||
|
||||
<programlisting>EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
<programlisting role="JAVA" language="JAVA">EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
|
||||
String hqlDelete = "delete Customer where name = :oldName";
|
||||
|
@ -103,13 +103,13 @@ entityManager.close();</programlisting>
|
|||
<para>The <literal>int</literal> value returned by the
|
||||
<literal>Query.executeUpdate()</literal> method indicate the number of
|
||||
entities effected by the operation. This may or may not correlate with the
|
||||
number of rows effected in the database. An EJB-QL bulk operation might
|
||||
number of rows effected in the database. A JP-QL bulk operation might
|
||||
result in multiple actual SQL statements being executed, for
|
||||
joined-subclass, for example. The returned number indicates the number of
|
||||
actual entities affected by the statement. Going back to the example of
|
||||
joined-subclass, a delete against one of the subclasses may actually
|
||||
result in deletes against not just the table to which that subclass is
|
||||
mapped, but also the "root" table and potentially joined-subclass tables
|
||||
further down the inheritence hierarchy.</para>
|
||||
</sect1>
|
||||
further down the inheritance hierarchy.</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -669,10 +669,10 @@ EntityManagerFactory programmaticEmf =
|
|||
<class>org.hibernate.ejb.test.Distributor</class>
|
||||
<class>org.hibernate.ejb.test.Item</class>
|
||||
<properties>
|
||||
<property name="<literal>javax.persistence.jdbc.driver</literal>" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="<literal>javax.persistence.jdbc.user</literal>" value="sa"/>
|
||||
<property name="<literal>javax.persistence.jdbc.password</literal>" value=""/>
|
||||
<property name="<literal>javax.persistence.jdbc.url</literal>" value="jdbc:hsqldb:."/>
|
||||
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="javax.persistence.jdbc.user" value="sa"/>
|
||||
<property name="javax.persistence.jdbc.password" value=""/>
|
||||
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:."/>
|
||||
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/
|
||||
<property name="hibernate.max_fetch_depth" value="3"/>
|
||||
|
||||
|
@ -857,7 +857,7 @@ EntityManagerFactory emf =
|
|||
<classname>Persistence</classname> class is bootstrap class to create an
|
||||
entity manager factory.</para>
|
||||
|
||||
<programlisting role="JAVA" language="JAVA">// Use persistence.xml configuration
|
||||
<programlisting role="JAVA" language="JAVA">// Use persistence.xml configuration
|
||||
EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1")
|
||||
EntityManager em = emf.createEntityManager(); // Retrieve an application managed entity manager
|
||||
// Work with the EM
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
<literal>new</literal> operator) it is in <literal>new</literal> state.
|
||||
You can make it persistent by associating it to an entity manager:</para>
|
||||
|
||||
<programlisting>DomesticCat fritz = new DomesticCat();
|
||||
<programlisting language="JAVA" role="JAVA">DomesticCat fritz = new DomesticCat();
|
||||
fritz.setColor(Color.GINGER);
|
||||
fritz.setSex('M');
|
||||
fritz.setName("Fritz");
|
||||
|
@ -93,7 +93,7 @@ em.persist(fritz);</programlisting>
|
|||
<para>Load an entity instance by its identifier value with the entity
|
||||
manager's <code>find()</code> method:</para>
|
||||
|
||||
<programlisting>cat = em.find(Cat.class, catId);
|
||||
<programlisting language="JAVA" role="JAVA">cat = em.find(Cat.class, catId);
|
||||
|
||||
// You may need to wrap the primitive identifiers
|
||||
long catId = 1234;
|
||||
|
@ -105,7 +105,7 @@ em.find( Cat.class, new Long(catId) );</programlisting>
|
|||
useful to link a child to its parent without having to load the
|
||||
parent.</para>
|
||||
|
||||
<programlisting>child = new Child();
|
||||
<programlisting language="JAVA" role="JAVA">child = new Child();
|
||||
child.SetName("Henry");
|
||||
Parent parent = em.getReference(Parent.class, parentId); //no query to the DB
|
||||
child.setParent(parent);
|
||||
|
@ -118,7 +118,7 @@ em.persist(child);</programlisting>
|
|||
refreshed unless you specify <literal>REFRESH</literal> as a cascade style
|
||||
of any associations:</para>
|
||||
|
||||
<programlisting>em.persist(cat);
|
||||
<programlisting language="JAVA" role="JAVA">em.persist(cat);
|
||||
em.flush(); // force the SQL insert and triggers to run
|
||||
em.refresh(cat); //re-read the state (after the trigger executes)</programlisting>
|
||||
</section>
|
||||
|
@ -145,7 +145,7 @@ em.refresh(cat); //re-read the state (after the trigger executes)</programlistin
|
|||
the query. Queries are always created using the current entity
|
||||
manager:</para>
|
||||
|
||||
<programlisting>List<?> cats = em.createQuery(
|
||||
<programlisting language="JAVA" role="JAVA">List<?> cats = em.createQuery(
|
||||
"select cat from Cat as cat where cat.birthdate < ?1")
|
||||
.setParameter(1, date, TemporalType.DATE)
|
||||
.getResultList();
|
||||
|
@ -176,7 +176,7 @@ Cat mother = (Cat) em.createQuery(
|
|||
type-safe approach is the Criteria API explained in <xref
|
||||
linkend="querycriteria" />.</para>
|
||||
|
||||
<programlisting>CriteriaQuery<Cat> criteria = builder.createQuery( Cat.class );
|
||||
<programlisting language="JAVA" role="JAVA">CriteriaQuery<Cat> criteria = builder.createQuery( Cat.class );
|
||||
Root<Cat> cat = criteria.from( Cat.class );
|
||||
criteria.select( cat );
|
||||
criteria.where( builder.lt( cat.get( Cat_.birthdate ), catDate ) );
|
||||
|
@ -186,7 +186,7 @@ List<Cat> cats = em.createQuery( criteria ).getResultList(); //notice no d
|
|||
using JP-QL (note that it's not as type-safe as the compiler has to
|
||||
trust you with the return type.</para>
|
||||
|
||||
<programlisting>//No downcasting since we pass the return type
|
||||
<programlisting language="JAVA" role="JAVA">//No downcasting since we pass the return type
|
||||
List<Cat> cats = em.createQuery(
|
||||
"select cat from Cat as cat where cat.birthdate < ?1", Cat.class)
|
||||
.setParameter(1, date, TemporalType.DATE)
|
||||
|
@ -205,7 +205,7 @@ List<Cat> cats = em.createQuery(
|
|||
<para>JPA queries can return tuples of objects if projection is used.
|
||||
Each result tuple is returned as an object array:</para>
|
||||
|
||||
<programlisting>Iterator kittensAndMothers = sess.createQuery(
|
||||
<programlisting language="JAVA" role="JAVA">Iterator kittensAndMothers = sess.createQuery(
|
||||
"select kitten, mother from Cat kitten join kitten.mother mother")
|
||||
.getResultList()
|
||||
.iterator();
|
||||
|
@ -233,7 +233,7 @@ while ( kittensAndMothers.hasNext() ) {
|
|||
persistent state (in other words, they are considered "read
|
||||
only"):</para>
|
||||
|
||||
<programlisting>Iterator results = em.createQuery(
|
||||
<programlisting language="JAVA" role="JAVA">Iterator results = em.createQuery(
|
||||
"select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
|
||||
"group by cat.color")
|
||||
.getResultList()
|
||||
|
@ -258,7 +258,7 @@ while ( results.hasNext() ) {
|
|||
in the query string. Named parameters should be preferred, they are
|
||||
more robust and easier to read and understand:</para>
|
||||
|
||||
<programlisting>// Named parameter (preferred)
|
||||
<programlisting language="JAVA" role="JAVA">// Named parameter (preferred)
|
||||
Query q = em.createQuery("select cat from DomesticCat cat where cat.name = :name");
|
||||
q.setParameter("name", "Fritz");
|
||||
List cats = q.getResultList();
|
||||
|
@ -284,7 +284,7 @@ List cats = q.list();</programlisting>
|
|||
number of rows you want to retrieve and/or the first row you want to
|
||||
retrieve), use the following methods:</para>
|
||||
|
||||
<programlisting>Query q = em.createQuery("select cat from DomesticCat cat");
|
||||
<programlisting language="JAVA" role="JAVA">Query q = em.createQuery("select cat from DomesticCat cat");
|
||||
q.setFirstResult(20);
|
||||
q.setMaxResults(10);
|
||||
List cats = q.getResultList(); //return cats from the 20th position to 29th</programlisting>
|
||||
|
@ -298,20 +298,20 @@ List cats = q.getResultList(); //return cats from the 20th position to 29th</pro
|
|||
|
||||
<para>You may also define named queries through annotations:</para>
|
||||
|
||||
<programlisting>@javax.persistence.NamedQuery(name="eg.DomesticCat.by.name.and.minimum.weight",
|
||||
<programlisting language="JAVA" role="JAVA">@javax.persistence.NamedQuery(name="eg.DomesticCat.by.name.and.minimum.weight",
|
||||
query="select cat from eg.DomesticCat as cat where cat.name = ?1 and cat.weight > ?2")</programlisting>
|
||||
|
||||
<para>Parameters are bound programmatically to the named query, before
|
||||
it is executed:</para>
|
||||
|
||||
<programlisting>Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
|
||||
<programlisting language="JAVA" role="JAVA">Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
|
||||
q.setString(1, name);
|
||||
q.setInt(2, minWeight);
|
||||
List<?> cats = q.getResultList();</programlisting>
|
||||
|
||||
<para>You can also use the slightly more type-safe approach:</para>
|
||||
|
||||
<programlisting>Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight", Cat.class);
|
||||
<programlisting language="JAVA" role="JAVA">Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight", Cat.class);
|
||||
q.setString(1, name);
|
||||
q.setInt(2, minWeight);
|
||||
List<Cat> cats = q.getResultList();</programlisting>
|
||||
|
@ -335,7 +335,7 @@ List<Cat> cats = q.getResultList();</programlisting>
|
|||
remember that all entity columns have to be returned for this
|
||||
mechanism to work):</para>
|
||||
|
||||
<programlisting>@SqlResultSetMapping(name="getItem", entities =
|
||||
<programlisting language="JAVA" role="JAVA">@SqlResultSetMapping(name="getItem", entities =
|
||||
@EntityResult(entityClass=org.hibernate.ejb.test.Item.class, fields= {
|
||||
@FieldResult(name="name", column="itemname"),
|
||||
@FieldResult(name="descr", column="itemdescription")
|
||||
|
@ -358,7 +358,7 @@ item = (Item) q.getSingleResult(); //from a class columns names match the mappin
|
|||
<title>Query lock and flush mode</title>
|
||||
|
||||
<para>You can adjust the flush mode used when executing the query as
|
||||
well as define the lock mode used to load the entities. </para>
|
||||
well as define the lock mode used to load the entities.</para>
|
||||
|
||||
<para>Adjusting the flush mode is interesting when one must guaranty
|
||||
that a query execution will not trigger a flush operation. Most of the
|
||||
|
@ -367,7 +367,7 @@ item = (Item) q.getSingleResult(); //from a class columns names match the mappin
|
|||
<para>Adjusting the lock mode is useful if you need to lock the
|
||||
objects returns by the query to a certain level.</para>
|
||||
|
||||
<programlisting>query.setFlushMode(FlushModeType.COMMIT)
|
||||
<programlisting language="JAVA" role="JAVA">query.setFlushMode(FlushModeType.COMMIT)
|
||||
.setLockMode(LockModeType.PESSIMISTIC_READ);</programlisting>
|
||||
|
||||
<note>
|
||||
|
@ -492,7 +492,7 @@ item = (Item) q.getSingleResult(); //from a class columns names match the mappin
|
|||
<methodname>find()</methodname> it, and then manipulate it directly, while
|
||||
the persistence context is open:</para>
|
||||
|
||||
<programlisting>Cat cat = em.find( Cat.class, new Long(69) );
|
||||
<programlisting language="JAVA" role="JAVA">Cat cat = em.find( Cat.class, new Long(69) );
|
||||
cat.setName("PK");
|
||||
em.flush(); // changes to cat are automatically detected and persisted</programlisting>
|
||||
|
||||
|
@ -510,7 +510,7 @@ em.flush(); // changes to cat are automatically detected and persisted</program
|
|||
by Hibernate) by closing the EntityManager or in a more fine-grained
|
||||
approach by calling the <methodname>detach()</methodname> method.</para>
|
||||
|
||||
<programlisting>Cat cat = em.find( Cat.class, new Long(69) );
|
||||
<programlisting language="JAVA" role="JAVA">Cat cat = em.find( Cat.class, new Long(69) );
|
||||
...
|
||||
em.detach(cat);
|
||||
cat.setName("New name"); //not propatated to the database</programlisting>
|
||||
|
@ -530,7 +530,7 @@ cat.setName("New name"); //not propatated to the database</programlisting>
|
|||
for persistence of modifications made to detached instances using the
|
||||
<methodname>EntityManager.merge()</methodname> method:</para>
|
||||
|
||||
<programlisting>// in the first entity manager
|
||||
<programlisting language="JAVA" role="JAVA">// in the first entity manager
|
||||
Cat cat = firstEntityManager.find(Cat.class, catId);
|
||||
Cat potentialMate = new Cat();
|
||||
firstEntityManager.persist(potentialMate);
|
||||
|
@ -563,7 +563,7 @@ secondEntityManager.merge(mate); // update mate</programlisting>
|
|||
not a detached instance) to <literal>merge()</literal>, the entity manager
|
||||
will figure this out for you:</para>
|
||||
|
||||
<programlisting>// In the first entity manager
|
||||
<programlisting language="JAVA" role="JAVA">// In the first entity manager
|
||||
Cat cat = firstEntityManager.find(Cat.class, catID);
|
||||
|
||||
// In a higher layer of the application, detached
|
||||
|
@ -739,7 +739,7 @@ secondEntityManager.merge(mate); // save the new instance</programlisting>
|
|||
automatically using the explained routine unless
|
||||
<methodname>flush()</methodname> is called explicitly.</para>
|
||||
|
||||
<programlisting>em = emf.createEntityManager();
|
||||
<programlisting language="JAVA" role="JAVA">em = emf.createEntityManager();
|
||||
Transaction tx = em.getTransaction().begin();
|
||||
em.setFlushMode(FlushModeType.COMMIT); // allow queries to return stale state
|
||||
|
||||
|
@ -817,11 +817,11 @@ em.getTransaction().commit(); // flush occurs</programlisting>
|
|||
associated entity (or collection of entities), you must indicate that in
|
||||
the association annotation:</para>
|
||||
|
||||
<programlisting>@OneToOne(cascade=CascadeType.PERSIST)</programlisting>
|
||||
<programlisting language="JAVA" role="JAVA">@OneToOne(cascade=CascadeType.PERSIST)</programlisting>
|
||||
|
||||
<para>Cascading options can be combined:</para>
|
||||
|
||||
<programlisting>@OneToOne(cascade= { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH } )</programlisting>
|
||||
<programlisting language="JAVA" role="JAVA">@OneToOne(cascade= { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.REFRESH } )</programlisting>
|
||||
|
||||
<para>You may even use <literal>CascadeType.ALL</literal> to specify that
|
||||
all operations should be cascaded for a particular association. Remember
|
||||
|
@ -924,4 +924,137 @@ em.getTransaction().commit(); // flush occurs</programlisting>
|
|||
nobody changes the data underneath while pessimistic locks enforce the
|
||||
lock right away and keep it till the transaction is committed.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Caching</title>
|
||||
|
||||
<para>When the second-level cache is activated (see <xref
|
||||
linkend="setup-configuration-packaging" /> and the Hibernate Annotations
|
||||
reference documentation), Hibernate ensures it is used and properly
|
||||
updated. You can however adjust these settings by passing two
|
||||
properties:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>javax.persistence.cache.retrieveMode</literal> which
|
||||
accepts <literal><classname>CacheRetrieveMode</classname></literal>
|
||||
values</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>javax.persistence.cache.storeMode</literal> which
|
||||
accepts <classname>CacheStoreMode</classname> values</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para><classname>CacheRetrieveMode</classname> controls how Hibernate
|
||||
accesses information from the second-level cache: <literal>USE</literal>
|
||||
which is the default or <literal>BYPASS</literal> which means ignore the
|
||||
cache. <classname>CacheStoreMode</classname> controls how Hibernate pushes
|
||||
information to the second-level cache: <literal>USE</literal> which is the
|
||||
default and push data in the cache when reading from and writing to the
|
||||
database, <literal>BYPASS</literal> which does not insert new data in the
|
||||
cache (but can invalidate obsolete data) and
|
||||
<classname>REFRESH</classname> which does like default but also force data
|
||||
to be pushed to the cache on database read even if the data is already
|
||||
cached.</para>
|
||||
|
||||
<para>You can set these properties:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>on a particular <classname>EntityManager</classname> via the
|
||||
<methodname>setProperty</methodname> method</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>on a query via a query hint (<methodname>setHint</methodname>
|
||||
method)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>when calling <methodname>find()</methodname> and
|
||||
<methodname>refresh()</methodname> and passing the properties in the
|
||||
appropriate <classname>Map</classname></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>JPA also introduces an API to interrogate the second-level cache and
|
||||
evict data manually.</para>
|
||||
|
||||
<programlisting language="JAVA" role="JAVA">Cache cache = entityManagerFactory.getCache();
|
||||
|
||||
if ( cache.contains(User.class, userId) ) {
|
||||
//load it as we don't hit the DB
|
||||
}
|
||||
|
||||
cache.evict(User.class, userId); //manually evict user form the second-level cache
|
||||
cache.evict(User.class); //evict all users from the second-level cache
|
||||
cache.evictAll(); //purge the second-level cache entirely</programlisting>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Checking the state of an object</title>
|
||||
|
||||
<para>You can check whether an object is managed by the persistence
|
||||
context</para>
|
||||
|
||||
<programlisting language="JAVA" role="JAVA">entityManager.get(Cat.class, catId);
|
||||
...
|
||||
boolean isIn = entityManager.contains(cat);
|
||||
assert isIn;</programlisting>
|
||||
|
||||
<para>You can also check whether an object, an association or a property
|
||||
is lazy or not. You can do that independently of the underlying
|
||||
persistence provider: </para>
|
||||
|
||||
<programlisting language="JAVA" role="JAVA">PersistenceUtil jpaUtil = Persistence.getPersistenceUtil();
|
||||
if ( jpaUtil.isLoaded( customer.getAddress() ) {
|
||||
//display address if loaded
|
||||
}
|
||||
if ( jpaUtil.isLoaded( customer.getOrders ) ) {
|
||||
//display orders if loaded
|
||||
}
|
||||
if (jpaUtil.isLoaded(customer, "detailedBio") ) {
|
||||
//display property detailedBio if loaded
|
||||
}</programlisting>
|
||||
|
||||
<para>However, if you have access to the entityManagerFactory, we
|
||||
recommend you to use:</para>
|
||||
|
||||
<programlisting language="JAVA" role="JAVA">PersistenceUnitUtil jpaUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
|
||||
|
||||
Customer customer = entityManager.get( Customer.class, customerId );
|
||||
|
||||
if ( jpaUtil.isLoaded( customer.getAddress() ) {
|
||||
//display address if loaded
|
||||
}
|
||||
if ( jpaUtil.isLoaded( customer.getOrders ) ) {
|
||||
//display orders if loaded
|
||||
}
|
||||
if (jpaUtil.isLoaded(customer, "detailedBio") ) {
|
||||
//display property detailedBio if loaded
|
||||
}
|
||||
|
||||
log.debug( "Customer id {}", jpaUtil.getIdentifier(customer) );</programlisting>
|
||||
|
||||
<para>The performances are likely to be slightly better and you can get
|
||||
the identifier value from an object (using
|
||||
<methodname>getIdentifier()</methodname>).</para>
|
||||
|
||||
<note>
|
||||
<para>These are roughly the counterpart methods of
|
||||
<methodname>Hibernate.isInitialize</methodname>.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Native Hibernate API</title>
|
||||
|
||||
<para>You can always fall back to the underlying
|
||||
<classname>Session</classname> API from a given
|
||||
<classname>EntityManager</classname>:</para>
|
||||
|
||||
<programlisting language="JAVA" role="JAVA">Session session = entityManager.unwrap(Session.class);</programlisting>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
entity class with the <literal>@EntityListeners</literal>
|
||||
annotation:</para>
|
||||
|
||||
<programlisting>@Entity
|
||||
<programlisting role="JAVA" language="JAVA">@Entity
|
||||
@EntityListeners(class=Audit.class)
|
||||
public class Cat {
|
||||
@Id private Integer id;
|
||||
|
@ -221,7 +221,7 @@ public class LastUpdateListener {
|
|||
deployment descriptors. There is also an additional feature that can be
|
||||
useful: default event listeners.</para>
|
||||
|
||||
<programlisting><?xml version="1.0" encoding="UTF-8"?>
|
||||
<programlisting role="XML" language="XML"><?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
of the
|
||||
<interfacename>javax.persistence.EntityManagerFactory</interfacename></para>
|
||||
|
||||
<programlisting>CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder();</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder();</programlisting>
|
||||
|
||||
<para>The next step is to obtain a
|
||||
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. You
|
||||
|
@ -57,11 +57,11 @@
|
|||
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
|
||||
for this purpose.</para>
|
||||
|
||||
<programlisting>CriteriaQuery<T> createQuery(Class<T>)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<T> createQuery(Class<T>)</programlisting>
|
||||
|
||||
<programlisting>CriteriaQuery<Tuple> createTupleQuery()</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Tuple> createTupleQuery()</programlisting>
|
||||
|
||||
<programlisting>CriteriaQuery<Object> createQuery()</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Object> createQuery()</programlisting>
|
||||
|
||||
<para>Each serves a different purpose depending on the expected type of the
|
||||
query results.</para>
|
||||
|
@ -77,7 +77,7 @@
|
|||
<section id="querycriteria-typedquery">
|
||||
<title>Typed criteria queries</title>
|
||||
|
||||
<programlisting>CriteriaQuery<T> createQuery(Class<T>)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<T> createQuery(Class<T>)</programlisting>
|
||||
|
||||
<para>The type of the criteria query (aka the <T>) indicates the
|
||||
expected types in the query result. This might be an entity, an Integer,
|
||||
|
@ -106,7 +106,7 @@
|
|||
<area coords="4" id="ex.criteria.typedquery.entity.3" />
|
||||
</areaspec>
|
||||
|
||||
<programlisting>CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
|
||||
<programlisting role="JAVA" language="JAVA">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" ) );
|
||||
|
@ -160,7 +160,7 @@ for ( Person person : people ) { ... }</programlisting>
|
|||
<area coords="3" id="ex.criteria.typedquery.attr.2" />
|
||||
</areaspec>
|
||||
|
||||
<programlisting>CriteriaQuery<Integer> criteria = builder.createQuery( Integer.class );
|
||||
<programlisting role="JAVA" language="JAVA">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" ) );
|
||||
|
@ -195,7 +195,7 @@ for ( Integer age : ages ) { ... } </programlisting>
|
|||
<area coords="3" id="ex.criteria.typedquery.expr.1" />
|
||||
</areaspec>
|
||||
|
||||
<programlisting>CriteriaQuery<Integer> criteria = builder.createQuery( Integer.class );
|
||||
<programlisting role="JAVA" language="JAVA">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" ) );
|
||||
|
@ -239,7 +239,7 @@ Integer maxAge = em.createQuery( criteria ).getSingleResult();</programlisting>
|
|||
<area coords="5" id="ex.criteria.typedquery.array.2" />
|
||||
</areaspec>
|
||||
|
||||
<programlisting>CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
|
||||
<programlisting role="JAVA" language="JAVA">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 );
|
||||
|
@ -284,7 +284,7 @@ for ( Object[] values : valueArray ) {
|
|||
<area coords="5" id="ex.criteria.typedquery.array2.2" />
|
||||
</areaspec>
|
||||
|
||||
<programlisting>CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
|
||||
<programlisting role="JAVA" language="JAVA">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 );
|
||||
|
@ -351,7 +351,7 @@ for ( Object[] values : valueArray ) {
|
|||
</areaset>
|
||||
</areaspec>
|
||||
|
||||
<programlisting>public class PersonWrapper {
|
||||
<programlisting role="JAVA" language="JAVA">public class PersonWrapper {
|
||||
private final Long id;
|
||||
private final Integer age;
|
||||
public PersonWrapper(Long id, Integer age) {
|
||||
|
@ -433,7 +433,7 @@ for ( PersonWrapper person : people ) { ... }</programlisting>
|
|||
</areaset>
|
||||
</areaspec>
|
||||
|
||||
<programlisting>CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
|
||||
<programlisting role="JAVA" language="JAVA">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 );
|
||||
|
@ -493,7 +493,7 @@ for ( Tuple tuple : valueArray ) {
|
|||
<term>typed</term>
|
||||
|
||||
<listitem>
|
||||
<programlisting><X> X get(TupleElement<X> tupleElement)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA"><X> X get(TupleElement<X> tupleElement)</programlisting>
|
||||
|
||||
<para>This allows typed access to the underlying tuple elements.
|
||||
We see this in <xref linkend="ex-criteria-typedquery-tuple" /> in
|
||||
|
@ -508,9 +508,9 @@ for ( Tuple tuple : valueArray ) {
|
|||
<term>positional</term>
|
||||
|
||||
<listitem>
|
||||
<programlisting>Object get(int i)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">Object get(int i)</programlisting>
|
||||
|
||||
<programlisting><X> X get(int i, Class<X> type)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA"><X> X get(int i, Class<X> type)</programlisting>
|
||||
|
||||
<para>Very similar to what we saw in <xref
|
||||
linkend="ex-criteria-typedquery-array" /> and <xref
|
||||
|
@ -527,9 +527,9 @@ for ( Tuple tuple : valueArray ) {
|
|||
<term>aliased</term>
|
||||
|
||||
<listitem>
|
||||
<programlisting>Object get(String alias)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">Object get(String alias)</programlisting>
|
||||
|
||||
<programlisting><X> X get(String alias, Class<X> type)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA"><X> X get(String alias, Class<X> type)</programlisting>
|
||||
|
||||
<para>Again, only the second form here provides typing, because
|
||||
the user explicitly provides the typing on access. We have not
|
||||
|
@ -574,14 +574,14 @@ for ( Tuple tuple : valueArray ) {
|
|||
<methodname>from</methodname> methods on
|
||||
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>:</para>
|
||||
|
||||
<programlisting><X> Root<X> from(Class<X>)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA"><X> Root<X> from(Class<X>)</programlisting>
|
||||
|
||||
<programlisting><X> Root<X> from(EntityType<X>)</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA"><X> Root<X> from(EntityType<X>)</programlisting>
|
||||
|
||||
<example>
|
||||
<title>Adding a root</title>
|
||||
|
||||
<programlisting>CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
// create and add the root
|
||||
person.from( Person.class );
|
||||
...</programlisting>
|
||||
|
@ -593,7 +593,7 @@ person.from( Person.class );
|
|||
product</ulink> between the newly added root and the others. Here is an
|
||||
example matching all single men and all single women:</para>
|
||||
|
||||
<programlisting>CriteriaQuery query = builder.createQuery();
|
||||
<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(
|
||||
|
@ -620,7 +620,7 @@ query.where( builder.and( menRestriction, womenRestriction ) );</programlisting>
|
|||
<example id="criteria-join-singular">
|
||||
<title>Example with Embedded and ManyToOne</title>
|
||||
|
||||
<programlisting>CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
<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 );
|
||||
|
@ -632,7 +632,7 @@ Join<Address,Country> addressCountry = personAddress.join( Address_.countr
|
|||
<example id="criteria-join-plural">
|
||||
<title>Example with Collections</title>
|
||||
|
||||
<programlisting>CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
<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 );
|
||||
|
@ -652,7 +652,7 @@ Join<Order,LineItem> orderLines = orders.join( Order_.lineItems );
|
|||
<example id="criteria-fetch-singular">
|
||||
<title>Example with Embedded and ManyToOne</title>
|
||||
|
||||
<programlisting>CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
<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 );
|
||||
|
@ -672,7 +672,7 @@ Join<Address,Country> addressCountry = personAddress.fetch( Address_.count
|
|||
<example id="criteria-fetch-plural">
|
||||
<title>Example with Collections</title>
|
||||
|
||||
<programlisting>CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
<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 );
|
||||
|
@ -704,7 +704,7 @@ Join<Order,LineItem> orderLines = orders.fetch( Order_.lineItems );
|
|||
<area coords="7" id="ex.criteria.param.3" />
|
||||
</areaspec>
|
||||
|
||||
<programlisting>CriteriaQuery<Person> criteria = build.createQuery( Person.class );
|
||||
<programlisting role="JAVA" language="JAVA">CriteriaQuery<Person> criteria = build.createQuery( Person.class );
|
||||
Root<Person> personRoot = criteria.from( Person.class );
|
||||
criteria.select( personRoot );
|
||||
ParameterExpression<String> eyeColorParam = builder.parameter( String.class );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
|
@ -22,18 +22,22 @@
|
|||
~ 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">
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter id="queryhql">
|
||||
<title>EJB-QL: The Object Query Language</title>
|
||||
<title>JP-QL: The Object Query Language</title>
|
||||
|
||||
<para>
|
||||
EJB3-QL has been heavily inspired by HQL, the native Hibernate Query Language. Both
|
||||
are therefore very close to SQL, but portable and independent of the database schema.
|
||||
People familiar with HQL shouldn't have any problem using EJB-QL. Actually, you
|
||||
use the same query API for EJB-QL and HQL queries. Portable EJB3 applications however
|
||||
should stick to EJB-QL or similar vendor extensions are needed.
|
||||
</para>
|
||||
<para>The Java Persistence Query Language (JP-QL) has been heavily inspired
|
||||
by HQL, the native Hibernate Query Language. Both are therefore very close
|
||||
to SQL, but portable and independent of the database schema. People familiar
|
||||
with HQL shouldn't have any problem using JP-QL. In fact HQL is a strict
|
||||
superset of JP-QL and you use the same query API for both types of queries.
|
||||
Portable JPA applications however should stick to JP-QL.</para>
|
||||
|
||||
<note>
|
||||
<para>For a type-safe approach to query, we highly recommend you to use
|
||||
the Criteria query, see <xref linkend="querycriteria" />.</para>
|
||||
</note>
|
||||
|
||||
<sect1 id="queryhql-casesensitivity">
|
||||
<title>Case Sensitivity</title>
|
||||
|
@ -45,7 +49,7 @@
|
|||
<literal>org.hibernate.eg.Foo</literal> and <literal>foo.barSet</literal>
|
||||
is not <literal>foo.BARSET</literal>.</para>
|
||||
|
||||
<para>This manual uses lowercase EJBQL keywords. Some users find queries
|
||||
<para>This manual uses lowercase JP-QL keywords. Some users find queries
|
||||
with uppercase keywords more readable, but we find this convention ugly
|
||||
when embedded in Java code.</para>
|
||||
</sect1>
|
||||
|
@ -53,28 +57,28 @@
|
|||
<sect1 id="queryhql-from">
|
||||
<title>The from clause</title>
|
||||
|
||||
<para>The simplest possible EJB-QL query is of the form:</para>
|
||||
<para>The simplest possible JP-QL query is of the form:</para>
|
||||
|
||||
<programlisting>select c from eg.Cat c</programlisting>
|
||||
|
||||
<para>which simply returns all instances of the class
|
||||
<literal>eg.Cat</literal>. Unlike HQL, the select clause is not optional
|
||||
in EJB-QL. We don't usually need to qualify the class name, since the
|
||||
in JP-QL. We don't usually need to qualify the class name, since the
|
||||
entity name defaults to the unqualified class name
|
||||
(<literal>@Entity</literal>). So we almost always just write:</para>
|
||||
|
||||
<programlisting>select c from Cat c</programlisting>
|
||||
|
||||
<para>As you may have noticed you can assign aliases to classes, the
|
||||
<literal>as</literal> keywork is optional. An alias allows you to refer
|
||||
to <literal>Cat</literal> in other parts of the query.</para>
|
||||
<literal>as</literal> keywork is optional. An alias allows you to refer to
|
||||
<literal>Cat</literal> in other parts of the query.</para>
|
||||
|
||||
<programlisting>select cat from Cat as cat</programlisting>
|
||||
|
||||
<para>Multiple classes may appear, resulting in a cartesian product or
|
||||
"cross" join.</para>
|
||||
|
||||
<programlisting>select form, param from Formula as form, Parameter as param</programlisting>
|
||||
<programlisting>select from, param from Formula as form, Parameter as param</programlisting>
|
||||
|
||||
<para>It is considered good practice to name query aliases using an
|
||||
initial lowercase, consistent with Java naming standards for local
|
||||
|
@ -116,9 +120,9 @@
|
|||
<para>In addition, a "fetch" join allows associations or collections of
|
||||
values to be initialized along with their parent objects, using a single
|
||||
select. This is particularly useful in the case of a collection. It
|
||||
effectively overrides the fetching options in the associations and collection
|
||||
mapping metadata. See the Performance chapter of the Hibernate reference guide
|
||||
for more information.</para>
|
||||
effectively overrides the fetching options in the associations and
|
||||
collection mapping metadata. See the Performance chapter of the Hibernate
|
||||
reference guide for more information.</para>
|
||||
|
||||
<programlisting>select cat from Cat as cat
|
||||
inner join fetch cat.mate
|
||||
|
@ -141,15 +145,12 @@
|
|||
<literal>iterate()</literal>. Nor should <literal>fetch</literal> be used
|
||||
together with <literal>setMaxResults()</literal> or
|
||||
<literal>setFirstResult()</literal>. It is possible to create a cartesian
|
||||
product by join fetching more than one collection in a query (as in the example
|
||||
above), be careful the result of this product isn't bigger than you expect.
|
||||
Join fetching multiple collection roles also sometimes gives unexpected results for
|
||||
bag mappings, so be careful about how you formulate your queries in this case.</para>
|
||||
|
||||
<para>
|
||||
TODO: The last statement is useless and typical developer thinking, please elaborate.
|
||||
The word "sometimes" should never appear in any technical documentation.
|
||||
</para>
|
||||
product by join fetching more than one collection in a query (as in the
|
||||
example above), be careful the result of this product isn't bigger than
|
||||
you expect. Join fetching multiple collection roles gives unexpected
|
||||
results for bag mappings as it is impossible for Hibernate to
|
||||
differentiate legit duplicates of a given bag from artificial duplicates
|
||||
created by the multi-table cartesian product.</para>
|
||||
|
||||
<para>If you are using property-level lazy fetching (with bytecode
|
||||
instrumentation), it is possible to force Hibernate to fetch the lazy
|
||||
|
@ -200,7 +201,8 @@ from DomesticCat as mother
|
|||
inner join mother.mate as mate
|
||||
left outer join mother.kittens as offspr</programlisting>
|
||||
|
||||
<para>or as an actual typesafe Java object,</para>
|
||||
<para>or as an actual type-safe Java object (often called a view
|
||||
object),</para>
|
||||
|
||||
<programlisting>select new Family(mother, mate, offspr)
|
||||
from DomesticCat as mother
|
||||
|
@ -254,7 +256,8 @@ from Cat cat</programlisting>
|
|||
</itemizedlist>
|
||||
|
||||
<para>You may use arithmetic operators, concatenation, and recognized SQL
|
||||
functions in the select clause (dpending on configured dialect, HQL specific feature):</para>
|
||||
functions in the select clause (dpending on configured dialect, HQL
|
||||
specific feature):</para>
|
||||
|
||||
<programlisting>select cat.weight + sum(kitten.weight)
|
||||
from Cat cat
|
||||
|
@ -281,7 +284,7 @@ select count(distinct cat.name), count(cat) from Cat cat</programlisting>
|
|||
<para>returns instances not only of <literal>Cat</literal>, but also of
|
||||
subclasses like <literal>DomesticCat</literal>. Hibernate queries may name
|
||||
<emphasis>any</emphasis> Java class or interface in the
|
||||
<literal>from</literal> clause (portable EJB-QL queries should only name
|
||||
<literal>from</literal> clause (portable JP-QL queries should only name
|
||||
mapped entities). The query will return instances of all persistent
|
||||
classes that extend that class or implement the interface. The following
|
||||
query would return all persistent objects:</para>
|
||||
|
@ -342,7 +345,8 @@ where cat.mate = mate</programlisting>
|
|||
|
||||
<para>The special property (lowercase) <literal>id</literal> may be used
|
||||
to reference the unique identifier of an object. (You may also use its
|
||||
mapped identifer property name.). Note that this keyword is specific to HQL.</para>
|
||||
mapped identifer property name.). Note that this keyword is specific to
|
||||
HQL.</para>
|
||||
|
||||
<programlisting>select cat from Cat as cat where cat.id = 123
|
||||
|
||||
|
@ -426,15 +430,21 @@ where log.item.class = 'Payment' and log.item.id = payment.id</programlisting>
|
|||
of</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>exists</literal>, <literal>all</literal>,
|
||||
<literal>any</literal>, <literal>some</literal> (taking
|
||||
subqueries)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>"Simple" case, <literal>case ... when ... then ... else ...
|
||||
end</literal>, and "searched" case, <literal>case when ... then ...
|
||||
else ... end (specific to HQL)</literal></para>
|
||||
else ... end</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>string concatenation <literal>...||...</literal> or
|
||||
<literal>concat(...,...) (use concat() for portable EJB-QL
|
||||
<literal>concat(...,...) (use concat() for portable JP-QL
|
||||
queries)</literal></para>
|
||||
</listitem>
|
||||
|
||||
|
@ -452,9 +462,9 @@ where log.item.class = 'Payment' and log.item.id = payment.id</programlisting>
|
|||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Any function or operator defined by EJB-QL 3.0:
|
||||
<literal>substring(), trim(), lower(), upper(), length(), locate(),
|
||||
abs(), sqrt(), bit_length()</literal></para>
|
||||
<para>Any function or operator: <literal>substring(), trim(), lower(),
|
||||
upper(), length(), locate(), abs(), sqrt(),
|
||||
bit_length()</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
|
@ -462,6 +472,13 @@ where log.item.class = 'Payment' and log.item.id = payment.id</programlisting>
|
|||
<literal>nullif()</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>TYPE ... in ...</literal>, where the first argument is
|
||||
an identifier variable and the second argument is the subclass to
|
||||
restrict polymorphism to (or a list of subclasses surrounded by
|
||||
parenthesis)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>cast(... as ...)</literal>, where the second argument
|
||||
is the name of a Hibernate type, and <literal>extract(... from
|
||||
|
@ -490,6 +507,11 @@ where log.item.class = 'Payment' and log.item.id = payment.id</programlisting>
|
|||
<literal>'1970-01-01 10:00:01.0'</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>JDBC escape syntax for dates (dependent on your JDBC driver
|
||||
support) (eg. <code>where date = {d '2008-12-31'}</code>)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Java <literal>public static final</literal> constants
|
||||
<literal>eg.Color.TABBY</literal></para>
|
||||
|
@ -548,7 +570,7 @@ where log.item.class = 'Payment' and log.item.id = payment.id</programlisting>
|
|||
supported when passed the element or index set of a collection
|
||||
(<literal>elements</literal> and <literal>indices</literal> functions) or
|
||||
the result of a subquery (see below). While subqueries are supported by
|
||||
EJB-QL, <literal>elements</literal> and <literal>indices</literal> are
|
||||
JP-QL, <literal>elements</literal> and <literal>indices</literal> are
|
||||
specific HQL features.</para>
|
||||
|
||||
<programlisting>select mother from Cat as mother, Cat as kit
|
||||
|
@ -567,7 +589,13 @@ where p.name = some elements(list.names)</programlisting>
|
|||
<literal>elements</literal>, <literal>indices</literal>,
|
||||
<literal>minindex</literal>, <literal>maxindex</literal>,
|
||||
<literal>minelement</literal>, <literal>maxelement</literal> - may only be
|
||||
used in the where clause in Hibernate3.</para>
|
||||
used in the where clause in Hibernate.</para>
|
||||
|
||||
<para>JP-QL lets you access the key or the value of a map by using the
|
||||
<literal>KEY()</literal> and <literal>VALUE()</literal> operations (even
|
||||
access the Entry object using <literal>ENTRY()</literal>)</para>
|
||||
|
||||
<programlisting>SELECT i.name, VALUE(p) FROM Item i JOIN i.photos p WHERE KEY(p) LIKE ‘%egret’</programlisting>
|
||||
|
||||
<para>In HQL, elements of indexed collections (arrays, lists, maps) may be
|
||||
referred to by index (in a where clause only):</para>
|
||||
|
@ -687,7 +715,7 @@ order by count(kitten) asc, sum(kitten.weight) desc</programlisting>
|
|||
<sect1 id="queryhql-subqueries">
|
||||
<title>Subqueries</title>
|
||||
|
||||
<para>For databases that support subselects, EJB-QL supports subqueries
|
||||
<para>For databases that support subselects, JP-QL supports subqueries
|
||||
within queries. A subquery must be surrounded by parentheses (often by an
|
||||
SQL aggregate function call). Even correlated subqueries (subqueries that
|
||||
refer to an alias in the outer query) are allowed.</para>
|
||||
|
@ -737,11 +765,11 @@ where not ( cat.name, cat.color ) in (
|
|||
</sect1>
|
||||
|
||||
<sect1 id="queryhql-examples">
|
||||
<title>EJB-QL examples</title>
|
||||
<title>JP-QL examples</title>
|
||||
|
||||
<para>Hibernate queries can be quite powerful and complex. In fact, the
|
||||
power of the query language is one of Hibernate's main selling points (and
|
||||
now EJB-QL). Here are some example queries very similar to queries that I
|
||||
now JP-QL). Here are some example queries very similar to queries that I
|
||||
used on a recent project. Note that most queries you will write are much
|
||||
simpler than these!</para>
|
||||
|
||||
|
@ -848,8 +876,8 @@ order by account.type.sortOrder, account.accountNumber, payment.dueDate</program
|
|||
<sect1 id="queryhql-bulk">
|
||||
<title>Bulk UPDATE & DELETE Statements</title>
|
||||
|
||||
<para>Hibernate now supports UPDATE and DELETE statements in HQL/EJB-QL. See <xref
|
||||
linkend="batch-direct" /> for details.</para>
|
||||
<para>Hibernate now supports UPDATE and DELETE statements in HQL/JP-QL.
|
||||
See <xref linkend="batch-direct" /> for details.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="queryhql-tipstricks">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
|
@ -22,8 +22,8 @@
|
|||
~ 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">
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter id="query_native">
|
||||
<title>Native query</title>
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
|||
database. This is useful if you want to utilize database specific features
|
||||
such as query hints or the CONNECT BY option in Oracle. It also provides a
|
||||
clean migration path from a direct SQL/JDBC based application to Hibernate.
|
||||
Note that Hibernate3 allows you to specify handwritten SQL (including stored
|
||||
Note that Hibernate allows you to specify handwritten SQL (including stored
|
||||
procedures) for all create, update, delete, and load operations (please
|
||||
refer to the reference guide for more information.)</para>
|
||||
|
||||
|
@ -42,10 +42,10 @@
|
|||
description will help the <literal>EntityManager</literal> to map your
|
||||
columns onto entity properties. This is done using the
|
||||
<literal>@SqlResultSetMapping</literal> annotation. Each
|
||||
<literal>@SqlResultSetMapping </literal>has a name wich is used when
|
||||
<literal>@SqlResultSetMapping </literal>has a name which is used when
|
||||
creating a SQL query on <literal>EntityManager</literal>.</para>
|
||||
|
||||
<programlisting>@SqlResultSetMapping(name="GetNightAndArea", entities={
|
||||
<programlisting role="JAVA" language="JAVA">@SqlResultSetMapping(name="GetNightAndArea", entities={
|
||||
@EntityResult(name="org.hibernate.test.annotations.query.Night", fields = {
|
||||
@FieldResult(name="id", column="nid"),
|
||||
@FieldResult(name="duration", column="night_duration"),
|
||||
|
@ -65,7 +65,7 @@
|
|||
<para>You can also define scalar results and even mix entity results and
|
||||
scalar results</para>
|
||||
|
||||
<programlisting>@SqlResultSetMapping(name="ScalarAndEntities",
|
||||
<programlisting role="JAVA" language="JAVA">@SqlResultSetMapping(name="ScalarAndEntities",
|
||||
entities={
|
||||
@EntityResult(name="org.hibernate.test.annotations.query.Night", fields = {
|
||||
@FieldResult(name="id", column="nid"),
|
||||
|
@ -103,7 +103,7 @@
|
|||
third one (not yet supported by Hibernate entity manager), returns pure
|
||||
scalar results.</para>
|
||||
|
||||
<programlisting>String sqlQuery = "select night.id nid, night.night_duration, night.night_date, area.id aid, "
|
||||
<programlisting role="JAVA" language="JAVA">String sqlQuery = "select night.id nid, night.night_duration, night.night_date, area.id aid, "
|
||||
+ "night.area_id, area.name from Night night, Area area where night.area_id = area.id "
|
||||
+ "and night.night_duration >= ?";
|
||||
Query q = entityManager.createNativeQuery(sqlQuery, "GetNightAndArea");
|
||||
|
@ -113,7 +113,7 @@ q.getResultList();</programlisting>
|
|||
<para>This native query returns nights and area based on the
|
||||
<literal>GetNightAndArea</literal> result set.</para>
|
||||
|
||||
<programlisting>String sqlQuery = "select * from tbl_spaceship where owner = ?";
|
||||
<programlisting role="JAVA" language="JAVA">String sqlQuery = "select * from tbl_spaceship where owner = ?";
|
||||
Query q = entityManager.createNativeQuery(sqlQuery, SpaceShip.class);
|
||||
q.setParameter( 1, "Han" );
|
||||
q.getResultList();</programlisting>
|
||||
|
@ -125,11 +125,11 @@ q.getResultList();</programlisting>
|
|||
<sect1>
|
||||
<title>Named queries</title>
|
||||
|
||||
<para>Native named queries share the same calling API than EJB-QL named
|
||||
<para>Native named queries share the same calling API than JP-QL named
|
||||
queries. Your code doesn't need to know the difference between the two.
|
||||
This is very useful for migration from SQL to EJB-QL:</para>
|
||||
This is very useful for migration from SQL to JP-QL:</para>
|
||||
|
||||
<programlisting>Query q = entityManager.createNamedQuery("getSeasonByNativeQuery");
|
||||
<programlisting role="JAVA" language="JAVA">Query q = entityManager.createNamedQuery("getSeasonByNativeQuery");
|
||||
q.setParameter( 1, name );
|
||||
Season season = (Season) q.getSingleResult();</programlisting>
|
||||
</sect1>
|
||||
|
|
|
@ -418,7 +418,7 @@
|
|||
mechanism behind the scenes. The common entity manager and transaction
|
||||
handling idiom looks like this:</para>
|
||||
|
||||
<programlisting>// Non-managed environment idiom
|
||||
<programlisting role="JAVA" language="JAVA">// Non-managed environment idiom
|
||||
EntityManager em = emf.createEntityManager();
|
||||
EntityTransaction tx = null;
|
||||
try {
|
||||
|
@ -501,7 +501,7 @@ finally {
|
|||
<para>If you use bean-managed transactions (BMT), the code will look
|
||||
like this:</para>
|
||||
|
||||
<programlisting>// BMT idiom
|
||||
<programlisting role="JAVA" language="JAVA">// BMT idiom
|
||||
@Resource public UserTransaction utx;
|
||||
@Resource public EntityManagerFactory factory;
|
||||
|
||||
|
@ -554,13 +554,13 @@ finally {
|
|||
<para>Our entity manager/transaction management idiom for CMT and EJB3
|
||||
container-use is reduced to this:</para>
|
||||
|
||||
<programlisting>//CMT idiom through injection
|
||||
<programlisting role="JAVA" language="JAVA">//CMT idiom through injection
|
||||
@PersistenceContext(name="sample") EntityManager em;</programlisting>
|
||||
|
||||
<para>Or this if you use Java Context and Dependency Injection
|
||||
(CDI).</para>
|
||||
|
||||
<programlisting>@Inject EntityManager em;</programlisting>
|
||||
<programlisting role="JAVA" language="JAVA">@Inject EntityManager em;</programlisting>
|
||||
|
||||
<para>In other words, all you have to do in a managed environment is to
|
||||
inject the <literal>EntityManager</literal>, do your data access work,
|
||||
|
@ -834,7 +834,7 @@ finally {
|
|||
the least efficient in terms of database access. It is the approach most
|
||||
similar to EJB2 entities:</para>
|
||||
|
||||
<programlisting>// foo is an instance loaded by a previous entity manager
|
||||
<programlisting role="JAVA" language="JAVA">// foo is an instance loaded by a previous entity manager
|
||||
em = factory.createEntityManager();
|
||||
EntityTransaction t = em.getTransaction();
|
||||
t.begin();
|
||||
|
@ -895,7 +895,7 @@ em.close();</programlisting>
|
|||
performance impact. The following examples show the idiom in a
|
||||
non-managed environment:</para>
|
||||
|
||||
<programlisting>// foo is an instance loaded earlier by the extended entity manager
|
||||
<programlisting role="JAVA" language="JAVA">// foo is an instance loaded earlier by the extended entity manager
|
||||
em.getTransaction.begin(); // new connection to data store is obtained and tx started
|
||||
foo.setProperty("bar");
|
||||
em.getTransaction().commit(); // End tx, flush and check version, disconnect</programlisting>
|
||||
|
@ -936,7 +936,7 @@ em.getTransaction().commit(); // End tx, flush and check version, disconnect</p
|
|||
persistence context and then merges the changes using
|
||||
<literal>EntityManager.merge()</literal>:</para>
|
||||
|
||||
<programlisting>// foo is an instance loaded by a non-extended entity manager
|
||||
<programlisting role="JAVA" language="JAVA">// foo is an instance loaded by a non-extended entity manager
|
||||
foo.setProperty("bar");
|
||||
entityManager = factory.createEntityManager();
|
||||
entityManager.getTransaction().begin();
|
||||
|
|
Loading…
Reference in New Issue