[Querydsl] Querydsl JPA CRUD Usages
Querydsl JPA CRUD Usages
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.
Querydsl for JPA 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.
Model and Query Type
Let’s assume that your project has the following domain type:
1 | import javax.persistence.Entity; |
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.
QCustomer
has a default instance variable which can be accessed as a static field:
1 | import static com.querydsl.core.types.PathMetadataFactory.*; |
Use query type:
1 | QCustomer customer = QCustomer.customer; |
Alternatively you can define your own Customer
variables like this:
1 | QCustomer customer = new QCustomer("myCustomer"); |
Read, Querying
The Querydsl JPA module supports both the JPA and the Hibernate API.
To use the JPA API you use JPAQuery instances for your queries like this:
1 | // where entityManager is a JPA EntityManager |
If you are using the Hibernate API instead, you can instantiate a HibernateQuery like this:
1 | // where session is a Hibernate session |
Both JPAQuery
and HibernateQuery
implement the JPQLQuery
interface.
For the examples of this chapter the queries are created via a JPAQueryFactory
instance. JPAQueryFactory
should be the preferred option to obtain JPAQuery
instances.
For the Hibernate API HibernateQueryFactory
can be used
To retrieve the customer with the first name Bob you would construct a query like this:
1 | QCustomer customer = QCustomer.customer; |
The selectFrom
call defines the query source and projection, the where part defines the filter
and fetchOne
tells Querydsl to return a single element. Easy, right?
To create a query with multiple sources you use the query like this:
1 | QCustomer customer = QCustomer.customer; |
And to use multiple filters use it like this
1 | queryFactory.selectFrom(customer) |
Or like this
1 | queryFactory.selectFrom(customer) |
In native JPQL form the query would be written like this:
1 | select customer from Customer as customer |
If you want to combine the filters via “or” then use the following pattern
1 | queryFactory.selectFrom(customer) |
Using joins
Querydsl supports the following join variants in JPQL: inner join
, join
, left join
and right join
. Join usage is typesafe, and follows the following pattern:
1 | QCat cat = QCat.cat; |
The native JPQL version of the query would be
1 | select cat from Cat as cat |
Another example
1 | queryFactory.selectFrom(cat) |
With the following JPQL version
1 | select cat from Cat as cat |
General usage
Use the the cascading methods of the JPQLQuery
interface like this
-
select: Set the projection of the query. (Not necessary if created via query factory)
-
from: Add the query sources here.
-
innerJoin, join, leftJoin, rightJoin, on: Add join elements using these constructs. For the join methods the first argument is the join source and the second the target (alias).
-
where: Add query filters, either in varargs form separated via commas or cascaded via the and-operator.
-
groupBy: Add group by arguments in varargs form.
-
having: Add having filters of the “group by” grouping as an varags array of Predicate expressions.
-
orderBy: Add 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.
-
limit, offset, restrict: Set the paging of the result. Limit for max results, offset for skipping rows and restrict for defining both in one call.
Ordering
The syntax for declaring ordering is
1 | QCustomer customer = QCustomer.customer; |
which is equivalent to the following native JPQL
1 | select customer |
Grouping
Grouping can be done in the following form
1 | queryFactory.select(customer.lastName).from(customer) |
Method groupBy
must combine select
methods.
which is equivalent to the following native JPQL
1 | select customer.lastName |
Update and Save
Update clauses
Update clauses in Querydsl JPA follow a simple update-set/where-execute form. Here are some examples:
1 | QCustomer customer = QCustomer.customer; |
1 | update customer |
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.
DML clauses in JPA don’t take JPA level cascade rules into account and don’t provide fine-grained second level cache interaction.
Subqueries
To create a subquery you use the static factory methods of JPAExpressions
and define the query parameters via from
, where etc.
1 | QDepartment department = QDepartment.department; |
Another example
1 | QEmployee employee = QEmployee.employee; |
Exposing the original query
If you need to tune the original Query before the execution of the query you can expose it like this:
1 | Query jpaQuery = queryFactory.selectFrom(employee).createQuery(); |
Using Native SQL in JPA queries
Querydsl supports Native SQL in JPA via the JPASQLQuery
class.
To use it, you must generate Querydsl query types for your SQL schema. This can be done for example with the following Maven configuration:
1 | <project> |
When the query types have successfully been generated into the location of your choice, you can use them in your queries.
Single column query:
1 | // serialization templates |
If you mix entity (e.g. QCat) and table (e.g. SAnimal) references in your query you need to make sure that they use the same variable names. SAnimal.animal has the variable name “animal”, so a new instance (new SAnimal(“cat”)) was used instead.
An alternative pattern could be
1 | QCat catEntity = QCat.cat; |
Query multiple columns:
1 | query = new JPASQLQuery<Void>(entityManager, templates); |
Query in SQL, but project as entity:
1 | query = new JPASQLQuery<Void>(entityManager, templates); |
Query with joins:
1 | query = new JPASQLQuery<Void>(entityManager, templates); |
Query and project into DTO:
1 | query = new JPASQLQuery<Void>(entityManager, templates); |
If you are using the Hibernate API instead of the JPA API, then use HibernateSQLQuery
instead.
References
[1] - https://querydsl.com/static/querydsl/latest/reference/html/ch02.html
[7] querydsl/querydsl: Unified Queries for Java - https://github.com/querydsl/querydsl
[8] Querydsl - Unified Queries for Java - https://querydsl.com/