ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [QueryDSL] select 절에서 조회 대상 지정 방법
    Java/JPA 2019. 7. 13. 22:33
    반응형

    QueryDSL을 이용하여 entity 전체를 가져오는 방법 말고, 조회 대상을 지정하여 원하는 값만 조회하는 것을 프로젝션이라고 합니다.

     

     프로젝션 대상이 하나일 경우에는 반환되는 타입이 프로젝션 대상의 타입입니다.

        @Test
        public void oneProjectionTest() {
            QMember m = QMember.member;
    
            query.select(m.name)
                    .from(m)
                    .fetch()
                    .stream()
                    .forEach(name -> log.info("name is : " + name));
        }

    위의 결과를 보면 Member 엔티티의 name은 String 타입이므로 프로젝션 대상이 하나일 때, List<String> 타입이 조회 결과로 반환되는 것을 볼 수 있습니다.


     만약 두 개 이상일 경우에는 어떤 타입이 반환될까요??

        @Test
        public void twoProjectionsTest() {
            QMember m = QMember.member;
    
            List<Tuple> results = query.select(m.name, m.age)
                    .where(m.age.goe(30L))
                    .from(m)
                    .fetch();
    
            results.stream()
                    .forEach(tuple -> {
                        log.info("name is " + tuple.get(0, String.class));
                        log.info("age is " + tuple.get(m.age));
                    });
        }

     프로젝션 대상이 둘 이상이라면 Tuple 타입을 반환합니다. Tuple을 조회할 때는 get() 메서드를 이용하면 됩니다.

    사용해보니 get() 으로 조회하는 방법으로 두 가지가 있는 것 같습니다.

     

    첫 번째 방법은 get() 메서드의 첫 번째 파라미터로 프로젝션 대상의 순번, 두 번째 파라미터는 해당 값의 타입을 명시하는 방법입니다.

    위의 예제 상에서 첫 번째 로그를 찍는 tuple.get(0, String.class) 코드입니다. select 대상에서 첫 번째 값으로 String 타입인 m.name 으로 지정하였으므로 0번 째 조회 결과를 가져오는 것입니다.

     

     두 번째 방법은 간단하게 조회한 쿼리 타입을 바로 지정하는 것입니다.

    로그를 찍는 코드상에서 tuple.get(m.age) 에 해당하는 방법입니다.

     

     저는 두 가지 방법 중에서 두 번째 방법이 더 가독성이 있어 보입니다.

     


     

     쿼리의 결과를 특정 객체로 받고 싶을 때는 QueryDSL에서 제공하는 Projections 클래스를 이용하면 됩니다.

     

    Projections 클래스를 이용하여 객체를 생성하는 방법 3가지

    • 프로퍼티 접근
    • 필드 직접 접근
    • 생성자 사용
    package com.edu.querydsl_training.domain;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class MemberDTO {
    
        private String name;
        private Long age;
    }
    

     

    예제를 위해 MemberDTO 클래스를 생성하였습니다. 해당 클래스는 단순하게 Member의 이름과 나이를 담는 DTO클래스입니다.

     


     

     먼저 프로퍼티를 이용한 접근 방법을 살펴보겠습니다.

    프로퍼티 접근 방법은 Projections.bean() 메서드를 이용하여 객체를 생성할 수 있고, setter() 메서드를 사용해서 값을 주입시켜줍니다.

        @Test
        public void simpleProjectionTest() {
            QMember m = QMember.member;
    
            query.select(Projections.bean(MemberDTO.class, m.name, m.age.as("age")))
                    .from(m)
                    .fetch()
                    .stream()
                    .forEach(memberDTO -> {
                        log.info("member name : " + memberDTO.getName());
                        log.info("member age : " + memberDTO.getAge());
                    });
        }

     

     

    필드 직접 접근 방법

    Projections.fields() 메서드를 이용하여 값을 주입시킵니다. 필드의 접근 지정자를 private로 지정해도 동작하며, setter() 메서드가 없어도 정상적으로 값이 주입됩니다.

        @Test
        public void simpleProjectionTest_2() {
            QMember m = QMember.member;
    
            query.select(Projections.fields(MemberDTO.class, m.name, m.age))
                    .from(m)
                    .fetch()
                    .stream()
                    .forEach(memberDTO -> {
                        log.info("member name : " + memberDTO.getName());
                        log.info("member age : " + memberDTO.getAge());
                    });
        }
    

     

    생성자를 이용하는 방법

    Projections.constructor() 메서드를 이용하면 됩니다. 해당 메서드는 생성자를 이용하여 객체에 값을 주입하며, 지정한 프로젝션과 생성자의 파라미터 순서가 같아야 합니다.

        @Test
        public void simpleProjectionTest_3() {
            QMember m = QMember.member;
    
            query.select(Projections.constructor(MemberDTO.class, m.name, m.age))
                    .from(m)
                    .fetch()
                    .stream()
                    .forEach(value -> {
                        log.info("member name : " + value.getName());
                        log.info("member age : " + value.getAge());
                    });
        }
    

     


      본 포스트는 김영한 님의 저서인 < 자바 ORM 표준 JPA 프로그래밍 > 책을 참고하여 작성하였습니다.

     

    반응형

    'Java > JPA' 카테고리의 다른 글

    [JPA] Auditing 설정 방법  (0) 2019.08.15
    QueryDSL 서브 쿼리 사용법  (0) 2019.07.14
    JPA QueryDSL 시작해보기  (0) 2019.07.11

    댓글

Designed by Tistory.