3.2. Result handling

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.

3.2.1. Returning multiple columns

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));
}}

3.2.2. Bean population

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();

3.2.3. Constructor usage

Constructor based row transformation can be used like this

List<UserDTO> dtos = query.select(
    Projections.bean(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();

3.2.4. Result aggregation

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 .