Back-End/Spring Boot
Spring Boot | QueryDSL | Projections
개발자티포
2025. 2. 5. 10:02
728x90
반응형
Projections는 QueryDSL에서 사용되는 유틸리티 클래스로, 쿼리 결과를 DTO 객체로 매핑할 때 사용된다.
- 엔티티가 아닌 DTO로 직접 조회 가능
- Setter, 생성자, 필드 기반 매핑 지원
- JPA 엔티티와 DTO를 분리하여 유지보수성을 향상
1. Projections.fields()
특징
- DTO의 필드 이름과 쿼리에서 가져오는 필드 이름이 정확히 일치해야 한다.
- 필드에 Setter가 필요 없다.
- 기본 생성자가 필요 없다.
- 명시적으로 필드 매핑이 필요할 경우 Expressions.as()를 사용한다.
예제
List<MyDto> result = queryFactory
.select(Projections.fields(MyDto.class,
qUser.username,
qUser.age,
qUser.email.as("emailAddress") // 필드명이 다르면 매핑 필요
))
.from(qUser)
.fetch();
장점
✅ Setter가 없어도 동작함 (필드에 직접 값이 주입됨)
✅ 기본 생성자 없어도 됨
✅ 일부 필드만 매핑 가능
단점
❌ DTO의 필드명과 QueryDSL의 필드명이 정확히 일치해야 함
❌ 필드명이 다를 경우 Expressions.as()를 사용해야 함
2. Projections.bean()
특징
- DTO의 필드 이름과 쿼리 필드 이름이 정확히 일치해야 한다.
- 필드에 Setter가 필요하다.
- 기본 생성자가 필요하다.
- 필드명이 다르면 Expressions.as()로 매핑해야 한다.
예제
List<MyDto> result = queryFactory
.select(Projections.bean(MyDto.class,
qUser.username,
qUser.age,
qUser.email.as("emailAddress") // 필드명이 다르면 매핑 필요
))
.from(qUser)
.fetch();
장점
✅ 명확한 매핑 가능 (Setter를 통한 값 주입)
✅ 일부 필드만 매핑 가능
단점
❌ Setter가 필요함 (Setter 없는 불변 객체 사용 불가)
❌ 기본 생성자가 필요함
❌ 필드명이 다르면 Expressions.as()를 사용해야 함
3. Projections.constructor()
특징
- DTO의 생성자 파라미터 순서대로 값을 주입한다.
- 기본 생성자가 필요 없다.
- Setter가 필요 없다.
- 필드명이 달라도 상관없다.
- 단, 생성자 파라미터 순서와 타입이 정확히 맞아야 한다.
예제
List<MyDto> result = queryFactory
.select(Projections.constructor(MyDto.class,
qUser.username,
qUser.age,
qUser.email // 필드명이 달라도 됨
))
.from(qUser)
.fetch();
장점
✅ Setter 필요 없음 (불변 객체 사용 가능)
✅ 기본 생성자 필요 없음
✅ 필드명이 달라도 됨 (필드명이 달라도 생성자 파라미터 순서대로 주입)
단점
❌ 생성자 파라미터 개수와 타입이 정확해야 함 (순서가 바뀌면 오류 발생)
❌ DTO 필드 일부만 선택적으로 매핑하기 어려움
1. @QueryProjection을 활용한 DTO 매핑
특징
- 컴파일 타임에 타입 검사를 수행하여 안전하다.
- 필드명이 일치할 필요 없음 → 생성자 파라미터에 맞게 자동 매핑됨.
- 불변 객체(Immutable DTO) 사용 가능 → final 필드도 활용 가능.
- QueryDSL의 QClass를 자동 생성하여 사용.
사용 방법
- DTO에 @QueryProjection 추가
- gradle 또는 maven에서 QueryDSL 코드 생성 설정
- QueryDSL에서 new QDTO()를 사용하여 조회
1️⃣ DTO에 @QueryProjection 적용
import com.querydsl.core.annotations.QueryProjection;
import lombok.Getter;
@Getter
public class UserDto {
private final String username;
private final int age;
private final String email;
@QueryProjection
public UserDto(String username, int age, String email) {
this.username = username;
this.age = age;
this.email = email;
}
}
- @QueryProjection을 붙이면 QueryDSL이 자동으로 QClass를 생성한다.
- final 필드를 사용할 수 있어 불변 객체(Immutable DTO) 작성이 가능하다.
2️⃣ QueryDSL 코드 생성 설정
Gradle 설정 (build.gradle.kts)
dependencies {
implementation("com.querydsl:querydsl-core")
implementation("com.querydsl:querydsl-jpa")
annotationProcessor("com.querydsl:querydsl-apt:5.0.0:jpa")
annotationProcessor("jakarta.persistence:jakarta.persistence-api")
annotationProcessor("jakarta.annotation:jakarta.annotation-api")
}
📌 annotationProcessor를 추가해야 QUserDto가 생성됨.
3️⃣ QueryDSL에서 QUserDto를 사용하여 조회
List<UserDto> result = queryFactory
.select(new QUserDto(qUser.username, qUser.age, qUser.email))
.from(qUser)
.fetch();
- new QUserDto(...) 를 사용하면 생성자 매개변수 타입과 개수를 자동 체크하므로, 컴파일 타임에 오류를 잡을 수 있다.
- Projections.constructor()처럼 생성자 기반 매핑이지만, 더 안전하다.
728x90
반응형