Querydsl provides two ways to customize results, FactoryExpressions for row based transformation and ResultTransformer for aggregation.
The com.querydsl.core.types.FactoryExpression
interface is used for Bean creation,
constructor invocation and for the creation of more complex objects. The functionality of the
FactoryExpression implementations of Querydsl can be accessed via the
com.querydsl.core.types.Projections
class.
For the com.querydsl.core.ResultTransformer
interface GroupBy
is the
main implementation.
Since Querydsl 3.0 the default type for multi-column results is com.querydsl.core.Tuple
.
Tuple provides provides a typesafe Map like interface to access column data from a Tuple row object.
List<Tuple> result = query.select(employee.firstName, employee.lastName) .from(employee).fetch(); for (Tuple row : result) { System.out.println("firstName " + row.get(employee.firstName)); System.out.println("lastName " + row.get(employee.lastName)); }}
This example could also have been written via the QTuple expression class like this
List<Tuple> result = query.select(new QTuple(employee.firstName, employee.lastName)) .from(employee).fetch(); for (Tuple row : result) { System.out.println("firstName " + row.get(employee.firstName)); System.out.println("lastName " + row.get(employee.lastName)); }}
In cases where Beans need to be populated based on the results of the query, Bean projections can be used like this
List<UserDTO> dtos = query.select(
Projections.bean(UserDTO.class, user.firstName, user.lastName)).fetch();
When fields should be directly used instead of setters the following variant can be used instead
List<UserDTO> dtos = query.select(
Projections.fields(UserDTO.class, user.firstName, user.lastName)).fetch();
Constructor based row transformation can be used like this
List<UserDTO> dtos = query.select(
Projections.constructor(UserDTO.class, user.firstName, user.lastName)).fetch();
As an alternative to the generic Constructor expression usage constructors
can also be annotated with the QueryProjection
annotation:
class CustomerDTO { @QueryProjection public CustomerDTO(long id, String name) { ... } }
And then you can use it like this in the query
QCustomer customer = QCustomer.customer; JPQLQuery query = new HibernateQuery(session); List<CustomerDTO> dtos = query.select(new QCustomerDTO(customer.id, customer.name)) .from(customer).fetch();
While the example is Hibernate specific, this feature is available in all modules.
If the type with the QueryProjection annotation is not an annotated entity type, you can use the constructor projection like in the example, but if the annotated type would be an entity type, then the constructor projection would need to be created via a call to the static create method of the query type:
@Entity class Customer { @QueryProjection public Customer(long id, String name) { ... } }
QCustomer customer = QCustomer.customer;
JPQLQuery query = new HibernateQuery(session);
List<Customer> dtos = query.select(QCustomer.create(customer.id, customer.name))
.from(customer).fetch();
Alternatively, if code generation is not an option, you can create a constructor projection like this:
List<Customer> dtos = query
.select(Projections.constructor(Customer.class, customer.id, customer.name))
.from(customer).fetch();
The
com.querydsl.core.group.GroupBy
class provides aggregation functionality which can be used to aggregate query results
in memory. Below are some usage examples.
Aggregating parent child relations
import static com.querydsl.core.group.GroupBy.*; Map<Integer, List<Comment>> results = query.from(post, comment) .where(comment.post.id.eq(post.id)) .transform(groupBy(post.id).as(list(comment)));
This will return a map of post ids to related comments.
Multiple result columns
Map<Integer, Group> results = query.from(post, comment) .where(comment.post.id.eq(post.id)) .transform(groupBy(post.id).as(post.name, set(comment.id)));
This will return a map of post ids to Group instances with access to post name and comment ids.
Group is the GroupBy equivalent to the Tuple interface.
More examples can be found here .