Java / / 2023. 1. 13. 16:00

[JPA] 프로젝션과 결과 반환 - @QueryProjection

반응형

해당 글은 김영한 님의 querydsl을 수강하며 정리하려고 적는 포스팅입니다.

 

생성자 + @QueryProjection

package study.querydsl.dto;

import com.querydsl.core.annotations.QueryProjection;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class MemberDto {

    private String username;
    private int age;

    @QueryProjection
    public MemberDto(String username, int age) {
        this.username = username;
        this.age = age;
    }
}
  • ./gradlew compileQuerydsl 또는 인텔리제이 gradle에서 compileQuerydsl 직접 실행
  • QMemberDto 생성 확인

 

@QueryProjection 활용

@Test
public void findDtoByQueryProjection() {
    List<MemberDto> result = queryFactory
            .select(new QMemberDto(member.username, member.age))
            .from(member)
            .fetch();

    for (MemberDto memberDto : result) {
        System.out.println("memberDto = " + memberDto);
    }
}

-----------------------------------------------------------------------------------
2023-01-13T15:38:07.064+09:00 DEBUG 18848 --- [           main] org.hibernate.SQL                        : 
    /* select
        member1.username,
        member1.age 
    from
        Member member1 */ select
            m1_0.username,
            m1_0.age 
        from
            member m1_0
            
memberDto = MemberDto(username=member1, age=10)
memberDto = MemberDto(username=member2, age=20)
memberDto = MemberDto(username=member3, age=30)
memberDto = MemberDto(username=member4, age=40)
  • 이 방법은 컴파일러로 타입을 체크할 수 있으므로 안정적인 방법이다.
  • 하지만 DTO에 QueryDSL 어노테이션을 유지해야만 하고, DTO까지 Q 파일로 생성해야 하는 단점이 있다.
  • 생성자를 그대로 가져가기 때문에 type까지 다 맞춰 준다. 따라서 안정적으로 생성이 가능하다.
    • (컴파일 시점에 타입이 맞지 않으면 오류가 발생한다.)

 

참고

constructor방식으로 결과 조회시 발생하는 오류는 런타임 오류이다. 컴파일 오류는 발생시키지 않아서 좋지 않다.

 

문제점

원래 Dto는 QueryDsl에 의존적이지 않지만, QueryDsl에 의존하게 된다.

  • Dto는 service, controller 등에서도 사용될 텐데, DTO가 아키텍처 상으로 순수하지 않다는 문제가 생긴다.
  • DTO를 깔끔하게 가지고 가고싶다면, 앞에서 설명한 feilds, constructor, setter 등을 사용하면 된다.

 

 

추가 - distinct

List<String> result = queryFactory
     .select(member.username).distinct()
     .from(member)
     .fetch();
  • distinct는 JPQL의 distinct와 같다.
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유