Querydsl은 결과 처리를 커스터마이징 하기 위해 행 기반 변환을 위한 FactoryExpressions과 집합을 위한 ResultTransformer를 제공하고 있다.
com.mysema.query.types.FactoryExpression
인터페이스는 빈 생성, 생성자 호출
그리고 더 복잡한 객체를 생성하기 위해 사용된다. com.mysema.query.types.Projections
클래스를
이용해서 FactoryExpression 구현체 기능에 접근할 수 있다.
com.mysema.query.ResultTransformer
인터페이스의 주요 구현체는 GroupBy
클래스이다.
Querydsl 3.0 부터 다중 컬럼 결과를 위한 기본 타입은 com.mysema.query.Tuple
이다.
Tuple은 타입에 안전한 Map을 제공하고, 이를 통해 Tuple 행 객체로부터 컬럼 데이터에 접근할 수 있다.
List<Tuple> result = query.from(employee).list(employee.firstName, employee.lastName); for (Tuple row : result) { System.out.println("firstName " + row.get(employee.firstName)); System.out.println("lastName " + row.get(employee.lastName)); }}
위 예제를 QTuple 클래스를 이용하면 다음과 같이 작성할 수 있다.
List<Tuple> result = query.from(employee).list(new QTuple(employee.firstName, employee.lastName)); for (Tuple row : result) { System.out.println("firstName " + row.get(employee.firstName)); System.out.println("lastName " + row.get(employee.lastName)); }}
쿼리 결과로부터 빈을 생성하고 싶다면, Bean 프로젝션을 사용하면 된다.
List<UserDTO> dtos = query.list(
Projections.bean(UserDTO.class, user.firstName, user.lastName));
setter 메서드 대신 필드에 직접 접근해야 한다면 다음 코드를 사용하면 된다.
List<UserDTO> dtos = query.list(
Projections.fields(UserDTO.class, user.firstName, user.lastName));
생성자 기반의 행 변환을 하는 방법은 다음과 같다.
List<UserDTO> dtos = query.list(
Projections.bean(UserDTO.class, user.firstName, user.lastName));
지네릭 생성자 표현식을 사용하는 대신, QueryProjection
어노테이션을 적용한 생성자를 사용할 수도 있다.
class CustomerDTO { @QueryProjection public CustomerDTO(long id, String name) { ... } }
그리고, 이 클래스를 다음과 같이 쿼리에서 사용 가능하다.
QCustomer customer = QCustomer.customer; JPQLQuery query = new HibernateQuery(session); List<CustomerDTO> dtos = query.from(customer).list(new QCustomerDTO(customer.id, customer.name));
이 예제가 Hibernate용 코드이긴 하지만, 다른 모든 모듈에서도 이 기능을 사용할 수 있다.
만약 QueryProjection 어노테이션이 적용된 타입이 엔티티(@Entity) 타입이 아니라면, 예제처럼 생성자 프로젝션을 사용할 수 있다. 하지만, 어노테이션이 적용된 타입이 엔티티(@Entity) 타입이라면 쿼리 타입의 정적 create 메서드를 실행해서 생성자 프로젝션을 만들 필요가 있다.
@Entity class Customer { @QueryProjection public Customer(long id, String name) { ... } }
QCustomer customer = QCustomer.customer;
JPQLQuery query = new HibernateQuery(session);
List<Customer> dtos = query.from(customer).list(QCustomer.create(customer.id, customer.name));
코드 생성을 할 수 없다면, 다음과 같이 생성자 프로젝션을 생성할 수 있다.
List<Customer> dtos = query.from(customer)
.list(ConstructorExpression.create(Customer.class, customer.id, customer.name));
com.mysema.query.group.GroupBy
클래스는 메모리에서 쿼리 결과에 대한 집합 연산을 수행하는
집합 함수를 제공한다. 다음은 사용 예이다.
부모 자식 관계에 대한 집합 연산
import static com.mysema.query.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)));
이 코드는 post id와 관련된 커멘트를 매핑한다.
다중 결과 컬럼
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)));
이 코드는 post id와 Group을 매핑한다. Group은 post name과 comment id를 갖는다.
Group은 GroupBy에 대해 Tuple 인터페이스와 같은 역할을 한다.
더 많은 예제는 여기를 참고한다.