프로젝션 결과 반환 중에서 가장 깔끔한 해결책이면서 약간 단점이 있는 @QueryProjection 에 대해서 알아보겠습니다.

생성자 + @QueryProjection

우선 DTO의 생성자에 @QueryProjection 를 붙여줍니다.

@Data
public class MemberDto {

    private String username;
    private int age;

    public MemberDto() {
    }

    **@QueryProjection**
    public MemberDto(String username, int age) {
        this.username = username;
        this.age = age;
    }

}

그리고 나서 Tasks → other -> compileJava 를 실행합니다. → 참고

Untitled

그러면 DTO 도 Q파일로 생성됩니다.

Untitled

@BeforeEach
void setUp() {
    queryFactory = new JPAQueryFactory(em);

    Team teamA = new Team("teamA");
    Team teamB = new Team("teamB");
    em.persist(teamA);
    em.persist(teamB);

    Member member1 = new Member("member1", 10, teamA);
    Member member2 = new Member("member2", 20, teamA);
    Member member3 = new Member("member3", 30, teamB);
    Member member4 = new Member("member4", 40, teamB);
    em.persist(member1);
    em.persist(member2);
    em.persist(member3);
    em.persist(member4);
}

@DisplayName("@QueryProjection")
@Test
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);
    }
}

코드를 작성하면 자동완성이 됩니다.

Untitled

생서자를 그대로 가져가기 때문에 타입을 알아서 맞춰줘 굉장히 안정적으로 코드를 다 가져갈 수 있습니다.

컴파일 시점에 타입이 안 맞으면 오류를 내주는 장점이 있죠.