티스토리 뷰

projections이란 쉽게 말해서 쿼리에 셀렉트 절에 들어갈 데이터(필드) 라고 보면된다고 한다.

 

엔티티 대신에 DTO를 편리하게 조회할 때 사용

전체 엔티티가 아니라 만약 회원 이름만 딱 조회하고 싶으면?

1. 인터페이스를 하나 만든다. 값을 얻고싶은 메소드만 만들어주기

package study.datajpa.repository;

public interface UsernameOnly {

    String getUsername();
}

 

2. repository에는 반환형태를 인터페이스 네임으로 붙여준다

    List<UsernameOnly> findProjectionByUsername(@Param("username")String username);
}

 

3.메소드를 사용해서 반환한다.

  @Test
    public void projections(){
        Team teamA = new Team("teamA");
        em.persist(teamA);

        Member m1 = new Member("m1", 0, teamA);
        Member m2 = new Member("m2", 0, teamA);

        em.persist(m1);
        em.persist(m2);

        em.flush();
        em.clear();

        //when
        List<UsernameOnly> result = memberRepository.findProjectionByUsername("m1");

        for (UsernameOnly usernameOnly : result) {
            System.out.println("usernameOnly = " + usernameOnly);
        }
    }

 

4. 로그를 확인하면 username 필드만 불러온다.

2024-03-07T13:59:46.162+09:00 DEBUG 3568 --- [           main] org.hibernate.SQL                        : 
    select
        m1_0.username 
    from
        member m1_0 
    where
        m1_0.username=?

 

만약 몇개를 고르고 싶으면

package study.datajpa.repository;

import org.springframework.beans.factory.annotation.Value;

public interface UsernameOnly {

    @Value("#{target.username + ' ' + target.age}")
    String getUsername();
}

 

1. 그러면 쿼리는 모든 필드를 가져온다.

2. 작성한 필드만 가져오게 된다.

 

 

 

 

 

클래스 기반으로 가져오기

package study.datajpa.repository;

public class UsernameOnlyDto {

    private final String username;

    public UsernameOnlyDto(String username) { //생성자의 파라미터로 필드를 정한다.
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

}

 

 

 

혹은 제네릭 타입으로도 가능하다

    <T> List<T> findProjectionByUsername(@Param("username")String username, Class<T> type);

 

        //when
        List<UsernameOnlyDto> result = memberRepository.findProjectionByUsername("m1", UsernameOnlyDto.class);

 

 

 

중첩구조로 가져오기

package study.datajpa.repository;

public interface NestedColosedProjections {

    String getUsername();
    TeamInfo getTeam();

    interface TeamInfo{
        String getName();
    }
}

 

레퍼지토리

    <T> List<T> findProjectionByUsername(@Param("username")String username, Class<T> type);

 

불러오기

        List<NestedColosedProjections> result = memberRepository.findProjectionByUsername("m1",NestedColosedProjections.class);

 

로그

    select
        m1_0.username,
        t1_0.team_id,
        t1_0.name 
    from
        member m1_0 
    left join
        team t1_0 
            on t1_0.team_id=m1_0.team_id 
    where
        m1_0.username=?

 

조인된 필드는 모두 가져오게 된다.

- 프로젝션 대상이 root 엔티티면, JPQL SELECT 절 최적화 가능

- 프로젝션 대상이 ROOT가 아니면

  - LEFT OUTER JOIN 처리

  - 모든 필드를 SELECT해서 엔티티로 조회한 다음에 계산

 

정리

- 프로젝션 대상이 root 엔티티면 유용하다.

- 프로젝션 대상이 root 엔티티를 넘어가면 JPQL SELECT 최적화가 안된다!

- 실무의 복잡한 쿼리를 해결하기에는 한계가 있따.

- 실무에서는 단순할 때만 사용하고, 조금만 복잡해지면 QueryDSL을 사용하자.

 

'dev_공부일지 > spring data JPA' 카테고리의 다른 글

네이티브 쿼리  (0) 2024.03.07
Query by Example  (0) 2024.03.07
Specifications(명세)(실무에서 잘 사용하지 않지만)  (0) 2024.03.06
data JPA 구현체 분석  (0) 2024.03.06
Web 확장 - 페이징과 정렬  (0) 2024.03.06
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함