1 분 소요


목차

  • 프로젝션과 결과 반환
    • 기본
    • DTO 조회
    • distinct


프로젝션과 결과 반환

PROJECTION : SELECT 절에서 어떤 컬럼들을 조회할지 대상을 지정하는 것.

기본

프로젝션 대상이 하나

List<String> result = queryFactory
        .select(member.username)
        .from(member)
        .fetch();
  • 프로젝션 대상이 하나면 타입을 명확하게 지정할 수 있음
  • 프로젝션 대상이 둘 이상이면 Tuple이나 DTO로 조회

Tuple 조회
com.querydsl.core.Tuple

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

for(Tuple tuple : result) {
    String username = tuple.get(member.username);
    Integer age = tuple.get(member.age);

    (soutv)...
}

DTO 조회

순수 JPA

MemberDto

@Data
@NoArgsConstructor
public class MemberDto {
    private String username;
    private int age;

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

순수 JPA에서 DTO 조회 코드

List<MemberDto> result = em.createQuery(
        "select new study.querydsl.dto.MemberDto(m.username, m.age) " +
                "from Member m", MemberDto.class)
        .getResultList();
  • 순수 JPA에서 DTO를 조회할 때는 new 명령어를 사용해야함
  • DTO의 package이름을 다 적어줘야해서 지저분함
  • 생성자 방식만 지원함

Querydsl 빈 생성

결과를 DTO 반환할 때 사용.

  • 프로퍼티 접근
  • 필드 직접 접근
  • 생성자 사용

프로퍼티 접근 - Setter

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

필드 직접 접근

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

별칭이 다를 때

@Data
public class UserDto {
    private String name;
    private int age;
}
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();
  • 프로퍼티나, 필드 접근 생성 방식에서 이름이 다를 때 해결 방안
  • ExpressionUtils.as(source, alias) : 필드나, 서브 쿼리에 별칭 적용
  • username.as("memberName") : 필드에 별칭 적용

생성자 사용

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

@QueryProjection

생성자 + @QueryProjection

@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
  • QMemberDto 생성 확인

@QueryProjection 활용

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

이 방법은 컴파일러로 타입을 체크할 수 있으므로 가장 안전한 방법이다.
다만, DTO에 QueryDSL 어노테이션을 유지해야 하는 점과 DTO까지 Q파일을 생성해야 하는 단점이 있다.

distinct

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

distinct는 JPQL의 distinct와 같다.


<출처 : 인프런 - 실전! Querydsl(김영한)>

댓글남기기