개요
QueryDSL로 검색 API를 구현하면서 엔티티가 아닌 검색 전용 DTO로 결과를 조회해야 했다.
DTO 매핑방식으로 두가지 선택지가 있다는 것을 알게되었다
- Projections.constructor()
- @QueryProjection
두 방식은 결과는 같아 보이지만,
안전성 · 유지보수성 · 오류 발견 시점에서 큰 차이가 있었다.
Projections.constructor 방식
.select(Projections.constructor(
TodoSearchResponse.class,
todo.title,
manager.id.countDistinct(),
comment.id.countDistinct()
))
특징
- DTO에 QueryDSL 의존성 X
- 생성자만 있으면 바로 사용 가능
- 설정이 간단
단점
- 생성자 파라미터 순서가 바뀌어도 컴파일 통과
- 타입이 애매하면 런타임 에러
- DTO 생성자 변경 시 IDE가 쿼리 오류를 잡아주지 못함
쿼리 오류를 실행해보기 전까지 알 수 없다
@QueryProjection 방식
DTO
@Getter
public class TodoSearchResponse {
private final String title;
private final long managerCount;
private final long commentCount;
@QueryProjection
public TodoSearchResponse(
String title,
long managerCount,
long commentCount
) {
this.title = title;
this.managerCount = managerCount;
this.commentCount = commentCount;
}
}
쿼리 사용
.select(new QTodoSearchResponse(
todo.title,
manager.id.countDistinct(),
comment.id.countDistinct()
))
특징
- 생성자 시그니처가 컴파일 타임에 검증
- 파라미터 개수/순서/타입이 틀리면 즉시 컴파일 에러
- DTO 변경 시 쿼리 코드에서 바로 오류 발생
쿼리 오류를 컴파일 시점에 잡을 수 있다
@QueryProjection을 선택한 이유
이번 검색 API는 다음 조건을 만족해야 했다.
- QueryDSL 기반 복잡한 검색
- 집계(countDistinct) 포함
- DTO 구조 변경 가능성 있음
이 상황에서는
실행 전에 오류를 잡을 수 있는 안정성이 가장 중요하다고 판단했다.
'Dev. > Spring' 카테고리의 다른 글
| [Spring] Spring Security + JWT로 로그인 기능 구현 (0) | 2025.12.09 |
|---|---|
| [Spring] Transactional 사용시 자가호출(Self-Invocation)이슈 (0) | 2025.12.08 |
| [Spring]왜 Security 의존성을 추가하면 API 호출시 401이 뜰까 (0) | 2025.12.06 |
| [Spring] AOP 정리 (0) | 2025.12.03 |
| [Spring] Interceptor 정리 (1) | 2025.12.02 |