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를 자동 생성하여 사용.

사용 방법

  1. DTO에 @QueryProjection 추가
  2. gradle 또는 maven에서 QueryDSL 코드 생성 설정
  3. 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
반응형