Spring

Querydsl 프로젝션 결과 반환

yougeun 2023. 4. 26. 00:32
728x90

MemberDto

@Data
@NoArgsConstructor
public class MemberDto {

    private String username;
    private int age;
  
    public MemberDto(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

UserDto

@Data
@NoArgsConstructor
public class UserDto {

    private String name;
    private int age;
}

1.프로젝션 대상이 1개일 때

List<String> result = queryFactory
                .select(member.username)
                .from(member)
                .fetch();

프로젝션 대상이 1개이면 타입을 명확하게 지정가능하다.

2.프로젝션이 둘 이상일 때

(1)Tuple로 조회

List<Tuple> result = queryFactory
                .select(member.username, member.age)
                .from(member)
                .fetch();
                
String username = tuple.get(member.username);
Integer age = tuple.get(member.age);

tuple은 querydsl에서 제공해주는 타입이므로 qeurydsl이 쓰이는 repository안에서만 쓰는 것이 좋다.

(2)Dto로 조회

1.프로퍼티 접근-Setter

List<MemberDto> result = queryFactory
                .select(Projections.bean(MemberDto.class,
                        member.username,
                        member.age))
                .from(member)
                .fetch();

MemberDto에 setter가 있어야 사용가능하다.

2.필드 직접접근

(1)  별칭이 같을 경우

List<MemberDto> result = queryFactory
                .select(Projections.fields(MemberDto.class,
                        member.username,
                        member.age))
                .from(member)
                .fetch();

(2) 별칭이 다를 경우

QMember memberSub = new QMember("memberSub");

        List<UserDto> result = queryFactory
                .select(Projections.fields(UserDto.class,
                        member.username.as("name"),
                        ExpressionUtils.as(JPAExpressions
                                .select(memberSub.age.max())
                                .from(memberSub),"age")))
                .from(member)
                .fetch();

서브 쿼리나 .as로 별칭을 dto의 변수 이름과 똑같이 만들어준다.

3.생성자 사용

List<MemberDto> result = queryFactory
                .select(Projections.constructor(MemberDto.class,
                        member.username,
                        member.age))
                .from(member)
                .fetch();

MemberDto에 해당하는 생성자가 있어야 사용가능하다.

3. @QueryProjection + 생성자

MemberDto

@Data
@NoArgsConstructor
public class MemberDto {

    private String username;
    private int age;

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

생성자위에 @QueryProjection어노테이션을 추가해준다.

이 후 컴파일을 다시하면 지정한 Dto도 Qtype으로 생성된다.

DTO Q파일 생성

List<MemberDto> result = queryFactory.select(new QMemberDto(member.username, member.age))
                .from(member)
                .fetch();

그 후 QMemberDto의 생성자를 이용하여 Dto로 조회가 가능하다.

이 방법은 컴파일러로 타입을 체크할 수 있는 가장 안전한 방법이다.

하지만 단점으로 DTO에 Querydsl의 어노테이션을 유지해야하는 점과 DTO까지 Q파일을 생성해야하는 단점이 있다.

728x90