fixed docs

This commit is contained in:
Timo Westkämper 2011-10-18 19:29:25 +03:00
parent 49480489d8
commit 9233f760f2
2 changed files with 616 additions and 3 deletions

View File

@ -344,7 +344,7 @@ from Cat as cat
<programlisting language="java"><![CDATA[
query.from(cat)
.leftJoin(cat.kittens, kitten)
.on(kitten.bodyWeight.gt(10.0))
.with(kitten.bodyWeight.gt(10.0))
.list(cat);
]]></programlisting>
@ -366,7 +366,7 @@ from Cat as cat
<para><emphasis>from :</emphasis> Define the query sources here.</para>
<para><emphasis>innerJoin, join, leftJoin, fullJoin, on</emphasis> : Define join elements using these constructs.
<para><emphasis>innerJoin, join, leftJoin, fullJoin, with</emphasis> : Define join elements using these constructs.
For the join methods the first argument is the join source and the second the target (alias).</para>
<para><emphasis>where :</emphasis> Define the query filters, either in varargs form separated via commas or
@ -610,4 +610,4 @@ List<CatDTO> catDTOs = query.from(cat)
</sect2>
</sect1>
</sect1>

View File

@ -0,0 +1,613 @@
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<sect1 id="jpa_integration" revision="1">
<title>Querying JPA</title>
<para>
Querydsl defines a general statically typed syntax for querying on top of
persisted domain model data. JDO and JPA are the primary integration
technologies for Querydsl. This guide describes how to use Querydsl
in combination with JPA/Hibernate.
</para>
<para>
Querydsl for JPA/Hibernate is an alternative to both JPQL and Criteria queries. It combines the dynamic nature
of Criteria queries with the expressiveness of JPQL and all that in a fully typesafe manner.
</para>
<sect2>
<title>Maven integration</title>
<para>
Add the following dependencies to your Maven project and make sure that
the Maven 2 repo of Mysema Source (http://source.mysema.com/maven2/releases) is accessible from your POM :
</para>
<programlisting language="xml"><![CDATA[
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
]]></programlisting>
<para>
And now, configure the Maven APT plugin :
</para>
<programlisting language="xml"><![CDATA[
<project>
<build>
<plugins>
...
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
</project>
]]></programlisting>
<para>
The JPAAnnotationProcessor finds domain types annotated with the
javax.persistence.Entity annotation and generates query types for them.
</para>
<para>
If you use Hibernate annotations in your domain types you should use
the APT processor com.mysema.query.apt.hibernate.HibernateAnnotationProcessor
instead.
</para>
<para>
Run clean install and you will get your Query
types generated into target/generated-sources/java.
</para>
<para>
If you use Eclipse, run mvn eclipse:eclipse to update your Eclipse project to include target/generated-sources/java
as a source folder.
</para>
<para>
Now you are able to construct JPQL query instances and instances of
the query domain model.
</para>
</sect2>
<sect2>
<title>Ant integration</title>
<para>Place the jar files from the full-deps bundle on your classpath and use the following tasks for Querydsl code generation :</para>
<programlisting language="xml"><![CDATA[
<!-- APT based code generation -->
<javac srcdir="${src}" classpathref="cp">
<compilerarg value="-proc:only"/>
<compilerarg value="-processor"/>
<compilerarg value="com.mysema.query.apt.jpa.JPAAnnotationProcessor"/>
<compilerarg value="-s"/>
<compilerarg value="${generated}"/>
</javac>
<!-- compilation -->
<javac classpathref="cp" destdir="${build}">
<src path="${src}"/>
<src path="${generated}"/>
</javac>
]]></programlisting>
<para>Replace <emphasis>src</emphasis> with your main source folder, <emphasis>generated</emphasis> with your folder for generated sources
and <emphasis>build</emphasis> with your target folder.</para>
</sect2>
<sect2>
<title>Generating the model from hbm.xml files</title>
<para>If you are using Hibernate with an XML based configuration, you can use the XML metadata to create your Querydsl model.</para>
<para>com.mysema.query.jpa.hibernate.HibernateDomainExporer provides the functionality for this :</para>
<programlisting language="java"><![CDATA[
HibernateDomainExporter exporter = new HibernateDomainExporter(
"Q", // name prefix
new File("target/gen3"), // target folder
configuration); // instance of org.hibernate.cfg.Configuration
exporter.export();
]]></programlisting>
<para>The HibernateDomainExporter needs to be executed within a classpath where the domain types are visible, since the property types are resolved
via reflection.</para>
<para>All JPA annotations are ignored, but Querydsl annotations such as @QueryInit and @QueryType are taken into account.</para>
</sect2>
<sect2>
<title>Using query types</title>
<para>
To create queries with Querydsl you need to instantiate variables and
Query implementations. We will start with the variables.
</para>
<para>
Let's assume that your project has the following domain type :
</para>
<programlisting language="java"><![CDATA[
@Entity
public class Customer {
private String firstName;
private String lastName;
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public void setFirstName(String fn){
firstName = fn;
}
public void setLastName(String ln)[
lastName = ln;
}
}
]]></programlisting>
<para>
Querydsl will generate a query type with the simple name QCustomer into the
same package as Customer. QCustomer can be used as a statically
typed variable in Querydsl queries as a representative for the
Customer type.
</para>
<para>
QCustomer has a default instance variable which can be accessed as a static
field :
</para>
<programlisting language="java"><![CDATA[
QCustomer customer = QCustomer.customer;
]]></programlisting>
<para>
Alternatively you can define your own Customer variables like this :
</para>
<programlisting language="java"><![CDATA[
QCustomer customer = new QCustomer("myCustomer");
]]></programlisting>
</sect2>
<sect2>
<title>Querying</title>
<para>The Querydsl JPA module supports both the JPA and the Hibernate API.</para>
<para>
To use the Hibernate API you use HibernateQuery instances for your queries like this :
</para>
<programlisting language="java"><![CDATA[
// where session is a Hibernate session
JPQLQuery query = new HibernateQuery (session);
]]></programlisting>
<para>If you are using the JPA API instead, you can instantiate a JPAQuery like this :</para>
<programlisting language="java"><![CDATA[
// where entityManager is a JPA EntityManager
JPQLQuery query = new JPAQuery (entityManager);
]]></programlisting>
<para>Both HibernateQuery and JPAQuery implement the JPQLQuery interface.</para>
<para>
The default configuration of JPAQuery is best suited for use with Hibernate. Whe using EclipseLink as the JPA provider, the
JPAQuery should be constructed like this :
</para>
<programlisting language="java"><![CDATA[
JPQLQuery query = new JPAQuery (entityManager, EclipseLinkTemplates.DEFAULT);
]]></programlisting>
<para>If you want to use the standard JPA 2 serialization then create the query like this :</para>
<programlisting language="java"><![CDATA[
JPQLQuery query = new JPAQuery (entityManager, JPQLTemplates.DEFAULT);
]]></programlisting>
<para>
To retrieve the customer with the first name Bob you would construct a
query like this :
</para>
<programlisting language="java"><![CDATA[
QCustomer customer = QCustomer.customer;
JPQLQuery query = new HibernateQuery (session);
Customer bob = query.from(customer)
.where(customer.firstName.eq("Bob"))
.uniqueResult(customer);
]]></programlisting>
<para>
The from call defines the query source, the where part defines the
filter and uniqueResult defines the projection and tells Querydsl
to return a single element. Easy, right?
</para>
<para>
To create a query with multiple sources you use the query like this :
</para>
<programlisting language="java"><![CDATA[
query.from(customer, company);
]]></programlisting>
<para>
And to use multiple filters use it like this
</para>
<programlisting language="java"><![CDATA[
query.from(customer)
.where(customer.firstName.eq("Bob"), customer.lastName.eq("Wilson"));
]]></programlisting>
<para>Or like this</para>
<programlisting language="java"><![CDATA[
query.form(customer)
.where(customer.firstName.eq("Bob").and(customer.lastName.eq("Wilson")));
]]></programlisting>
<para>In native JPQL form the query would be written like this : </para>
<programlisting>
from Customer as customer
where customer.firstName = "Bob" and customer.lastName = "Wilson"
</programlisting>
<para>If you want to combine the filters via "or" then use the following pattern</para>
<programlisting language="java"><![CDATA[
query.form(customer)
.where(customer.firstName.eq("Bob").or(customer.lastName.eq("Wilson")));
]]></programlisting>
</sect2>
<sect2>
<title>Using joins</title>
<para>Querydsl supports the following join variants in JPQL : inner join, join, left join and full join.
Join usage is typesafe, and follows the following pattern :</para>
<programlisting language="java"><![CDATA[
query.from(cat)
.innerJoin(cat.mate, mate)
.leftJoin(cat.kittens, kitten)
.list(cat);
]]></programlisting>
<para>The native JPQL version of the query would be </para>
<programlisting>
from Cat as cat
inner join cat.mate as mate
left outer join cat.kittens as kitten
</programlisting>
<para>Another example</para>
<programlisting language="java"><![CDATA[
query.from(cat)
.leftJoin(cat.kittens, kitten)
.on(kitten.bodyWeight.gt(10.0))
.list(cat);
]]></programlisting>
<para>With the following JPQL version</para>
<programlisting>
from Cat as cat
left join cat.kittens as kitten
with kitten.bodyWeight > 10.0
</programlisting>
</sect2>
<sect2>
<title>General usage</title>
<para>Use the the cascading methods of the JPQLQuery interface like this</para>
<para><emphasis>from :</emphasis> Define the query sources here.</para>
<para><emphasis>innerJoin, join, leftJoin, fullJoin, on</emphasis> : Define join elements using these constructs.
For the join methods the first argument is the join source and the second the target (alias).</para>
<para><emphasis>where :</emphasis> Define the query filters, either in varargs form separated via commas or
cascaded via the and-operator.</para>
<para><emphasis>groupBy :</emphasis> Define the group by arguments in varargs form.</para>
<para><emphasis>having :</emphasis> Define the having filter of the "group by" grouping as an varags array of
Predicate expressions.</para>
<para><emphasis>orderBy :</emphasis> Define the ordering of the result as an varargs array of order expressions.
Use asc() and desc() on numeric, string and other comparable expression to access the OrderSpecifier instances. </para>
<para><emphasis>limit, offset, restrict :</emphasis> Define the paging of the result. Limit for max results,
offset for skipping rows and restrict for defining both in one call.</para>
</sect2>
<sect2>
<title>Ordering</title>
<para>The syntax for declaring ordering is </para>
<programlisting language="java"><![CDATA[
query.from(customer)
.orderBy(customer.lastName.asc(), customer.firstName.desc())
.list(customer);
]]></programlisting>
<para>which is equivalent to the following native JPQL</para>
<programlisting>
from Customer as customer
order by customer.lastName asc, customer.firstName desc
</programlisting>
</sect2>
<sect2>
<title>Grouping</title>
<para>Grouping can be done in the following form</para>
<programlisting language="java"><![CDATA[
query.from(customer)
.groupBy(customer.lastName)
.list(customer.lastName);
]]></programlisting>
<para>which is equivalent to the following native JPQL</para>
<programlisting>
select customer.lastName
from Customer as customer
group by customer.lastName
</programlisting>
</sect2>
<sect2>
<title>Delete clauses</title>
<para>Delete clauses in Querydsl JPA follow a simple delete-where-execute form. Here are some examples :</para>
<programlisting language="java"><![CDATA[
QCustomer customer = QCustomer.customer;
// delete all customers
new HibernateDeleteClause(session, customer).execute();
// delete all customers with a level less than 3
new HibernateDeleteClause(session, customer).where(customer.level.lt(3)).execute();
]]></programlisting>
<para>The second parameter of the HibernateDeleteClause constructor is the entity to be deleted.
The where call is optional and the execute call performs the deletion and returns the amount of deleted entities.</para>
<para>For JPA based Delete usage, use the JPADeleteClause instead.</para>
</sect2>
<sect2>
<title>Update clauses</title>
<para>Update clauses in Querydsl JPA follow a simple update-set/where-execute form. Here are some examples :</para>
<programlisting language="java"><![CDATA[
QCustomer customer = QCustomer.customer;
// rename customers named Bob to Bobby
new HibernateUpdateClause(session, customer).where(customer.name.eq("Bob"))
.set(customer.name, "Bobby")
.execute();
]]></programlisting>
<para>The second parameter of the HibernateUpdateClause constructor is the entity to be updated.
The set invocations define the property updates in SQL-Update-style and the execute call performs
the Update and returns the amount of updated entities.</para>
<para>For JPA based Update usage, use the JPAUpdateClause instead.</para>
</sect2>
<sect2>
<title>Subqueries</title>
<para>To create a subquery you create a HibernateSubQuery instance, define the query parameters
via from, where etc and use
unique or list to create a subquery, which is just a type-safe Querydsl expression for the query.
unique is used for a unique (single) result and list for a list result.</para>
<programlisting language="java"><![CDATA[
query.from(department)
.where(department.employees.size().eq(
new HibernateSubQuery().from(d).unique(d.employees.size().max())
)).list(department);
]]></programlisting>
<para>Another example</para>
<programlisting language="java"><![CDATA[
query.from(employee)
.where(employee.weeklyhours.gt(
new HibernateSubQuery().from(employee.department.employees, e)
.where(e.manager.eq(employee.manager))
.unique(e.weeklyhours.avg())
)).list(employee);
]]></programlisting>
<para>For JPA based sub query usage, use the JPASubQuery instead.</para>
</sect2>
<sect2>
<title>Exposing the original query</title>
<para>If you need to do tune the original Query before the execution of the query you can expose it like this :</para>
<programlisting language="java"><![CDATA[
HibernateQuery query = new HibernateQuery(session);
org.hibernate.Query hibQuery = query.from(employee).createQuery(employee);
hibQuery.setResultTransformer(someTransformer);
List results = hibQuery.list();
]]></programlisting>
</sect2>
<sect2>
<title>Using Native SQL in Hibernate queries</title>
<para>Querydsl supports Native SQL in Hibernate via the HibernateSQLQuery class.</para>
<para>To use it, you must generate Querydsl query types for your SQL schema. This can be done for example
with the following Maven configuration : </para>
<programlisting language="xml"><![CDATA[
<plugin>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>export</goal>
</goals>
</execution>
</executions>
<configuration>
<jdbcDriver>org.apache.derby.jdbc.EmbeddedDriver</jdbcDriver>
<jdbcUrl>jdbc:derby:target/demoDB;create=true</jdbcUrl>
<packageName>com.mycompany.mydomain</packageName>
<targetFolder>${project.basedir}/target/generated-sources/java</targetFolder>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>${derby.version}</version>
</dependency>
</dependencies>
</plugin>
]]></programlisting>
<para>When the query types have successfully been generated into the location of your choice, you can use them in your
queries.
</para>
<para>Single column query :</para>
<programlisting language="java"><![CDATA[
// serialization templates
SQLTemplates templates = new DerbyTemplates();
// query types (S* for SQL, Q* for domain types)
SAnimal cat = new SAnimal("cat");
SAnimal mate = new SAnimal("mate");
QCat catEntity = QCat.cat;
HibernateSQLQuery query = new HibernateSQLQuery(session, templates);
List<String> names = query.from(cat).list(cat.name);
]]></programlisting>
<para>Query multiple columns :</para>
<programlisting language="java"><![CDATA[
query = new HibernateSQLQuery(session, templates);
List<Object[]> rows = query.from(cat).list(cat.id, cat.name);
]]></programlisting>
<para>Query all columns :</para>
<programlisting language="java"><![CDATA[
List<Object[]> rows = query.from(cat).list(cat.all());
]]></programlisting>
<para>Query in SQL, but project as entity : </para>
<programlisting language="java"><![CDATA[
query = new HibernateSQLQuery(session, templates);
List<Cat> cats = query.from(cat).orderBy(cat.name.asc()).list(catEntity);
]]></programlisting>
<para>Query with joins : </para>
<programlisting language="java"><![CDATA[
query = new HibernateSQLQuery(session, templates);
cats = query.from(cat)
.innerJoin(mate).on(cat.mateId.eq(mate.id))
.where(cat.dtype.eq("Cat"), mate.dtype.eq("Cat"))
.list(catEntity);
]]></programlisting>
<para>Query and project into DTO : </para>
<programlisting language="java"><![CDATA[
query = new HibernateSQLQuery(session, templates);
List<CatDTO> catDTOs = query.from(cat)
.orderBy(cat.name.asc())
.list(ConstructorExpression.create(CatDTO.class, cat.id, cat.name));
]]></programlisting>
<para>If you are using the JPA API instead of the Hibernate API, then use
JPASQLQuery instead of HibernateSQLQuery</para>
</sect2>
</sect1>