Projections 의 객체 생성방법 4가지

By | 2022년 7월 25일
Table of Contents

Projections 의 객체 생성방법 4가지

Projections 사용법에 대해 오해를 불러올 수 있다는 의견이 있어 문서 추가작성합니다.

Projections.bean()

기본 생성자(@NoArgsConstructor) + @Setter 를 이용해 객체를 생성합니다.

직관적이고 이해하기 쉽습니다.
약간의 성능 오버헤드가 있습니다.

@Setter 가 필수이므로, 불변객체가 될 수 없습니다.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class UserGroupByDto {
    private String username;
    private Long count;
}
    public List<UserGroupByDto> groupBy() {

        return jpaQueryFactory
                .select(
                        Projections.bean(
                                UserGroupByDto.class
                                , user.username
                                , user.count().as("count")
                        )
                )
                .from(user)
                .groupBy(user.username)
                .orderBy(user.username.asc())
                .fetch();
    }

Projections.fields()

@Setter 를 사용하지 않고 객체에 데이타를 직접 입력합니다.
기본 생성자(@NoArgsConstructor) 가 필요합니다.

@Getter
@NoArgsConstructor
public class UserGroupByDto {

    private String username;
    private Long count;

    private UserGroupByDto(String username, Long count) {
        throw new RuntimeException("Projections 을 이용해 객체 생성할 것");
    }
}
    public List<UserGroupByDto> groupBy() {

        return jpaQueryFactory
                .select(
                        Projections.fields(
                                UserGroupByDto.class
                                , user.username
                                , user.count().as("count")
                        )
                )
                .from(user)
                .groupBy(user.username)
                .orderBy(user.username.asc())
                .fetch();
    }

Projections.constructor()

생성자를 이용해 객체를 생성합니다.
@AllArgsConstructor 가 필수이고, @Setter 는 필요없습니다.
성능이 좋습니다.
변수명 기반 매칭이 아니라 순서기반 매칭으로 생성자와 순서를 일치시켜야 합니다.

@Getter
@AllArgsConstructor
public class UserGroupByDto {

    private String username;
    private Long count;
}
List<UserGroupByDto> users = queryFactory
    .select(Projections.constructor(UserGroupByDto.class,
        user.username,
        user.count))
    .from(user)
    .fetch();

@QueryProjection

@QueryProjection 을 지정해서 DTO 도 QClass 를 생성하도록 하고,
생성된 QClass 를 이용하는 방식입니다.
DTO 도 QClass 를 생성하게 되지만, 컴파일 타임 오류체크를 할 수 있고 성능이 좋습니다.

@QueryProjection 를 사용하므로, Querydsl의 의존성이 필요 없는 레이어에서도 해당 의존성이 필요하게 됩니다.

@Getter
@Setter
@NoArgsConstructor
public class UserGroupByDto {

    private String username;
    private Long count;

    @QueryProjection
    public UserGroupByDto(String username, Long count) {
        this.username = username;
        this.count = count;
    }
}
    public List<UserGroupByDto> groupBy() {

        return jpaQueryFactory
                .select(new QUserGroupByDto(
                                user.username
                                , user.count().as("count")
                        )
                )
                .from(user)
                .groupBy(user.username)
                .orderBy(user.username.asc())
                .fetch();
    }

답글 남기기