Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

Projections 본문

인프런/[인프런] Spring Data JPA

Projections

Seung__ 2021. 8. 31. 23:34
  • 엔티티 대신에 DTO를 편리하게 조회할 때 사용
  • 전체 엔티티가 아니라 딱 회원의 이름만 조회하고 싶은 경우!

 

 

1. closed Projection


  • 인터페이스만 생성하면 구현체는 SpringDataJpa가 만듦.
public interface UserNameOnly {

    String getUserName();
}
  • 사용 방법 : 아래와 같이 return type으로 인터페이스를 지정해주면 됨.
@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.findProjectionsByUserName("m1");
        for (UserNameOnly userNameOnly : result) {
            System.out.println("userNameOnly = " + userNameOnly);
        }
    }
  • 반환 타입을 보면 스프링이 구현체를 만들어서 넣어준 것을 확인 가능.
    select
        member0_.user_name as col_0_0_ 
    from
        member member0_ 
    where
        member0_.user_name=?
        
2021-08-31 22:55:31.844  INFO 34388 --- [           main] p6spy                                    : #1630418131844 | took 1ms | statement | connection 103| url jdbc:h2:tcp://localhost/~/datajpa
select member0_.user_name as col_0_0_ from member member0_ where member0_.user_name=?
select member0_.user_name as col_0_0_ from member member0_ where member0_.user_name='m1';
userNameOnly = org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap@258ac1e6

 

 

 

2. open Projection


  • DB에서 엔티티 전체를 가져와서 애플리케이션에서 원하는 데이터만 찍을 수 있음
public interface UserNameOnly {

    @Value("#{target.userName + ' ' + target.age}") //
    String getUserName();
}

 

 

3. Class 기반 projection


@Getter
public class UserNameOnlyDto {

    private String userName;

    public UserNameOnlyDto(String userName) {
        this.userName = userName;
    }
}
  • 파라미터 명(userName)을 가지고 분석함.
  • 해당 파라미터를 가져와서 생성자를 통해 DTO반환
  • Repository
List<UserNameOnlyDto> findProjectionsByUserName(@Param("userName") String userName);
  • Test
  List<UserNameOnlyDto> result = memberRepository.findProjectionsByUserName("m1");
        for (UserNameOnlyDto userNameOnly : result) {
            System.out.println("userNameOnly = " + userNameOnly);
        }

 

 

4. 동적 projection


  • Generic으로 넘기면 됨.
  • Repository
<T> List<T> findProjectionsByUsername(String username, Class<T> type);

 

 

5. 중첩 구조


  • 멤버랑 연관된 팀 까지 가져오기
public interface NestedClosedProjections {
    
    String getUserName(); //root --> 최적화 해서 가져옴
    TeamInfo getTeam(); //최적화 안하고 다가져옴
    
    interface TeamInfo{
        String getName();
    }
}
  • Repository
List<NestedClosedProjections> findProjectionsByUserName(@Param("userName") String userName);
  • Test
//when
        List<NestedClosedProjections> result = memberRepository.findProjectionsByUserName("m1");
        for (NestedClosedProjections userNameOnly : result) {
            System.out.println("userNameOnly = " + userNameOnly);
        }
  • root인 user는 최적화해서 UserName만 가져옴.
  • team은 outer join으로 가져옴
    select
        member0_.user_name as col_0_0_,
        team1_.team_id as col_1_0_,
        team1_.team_id as team_id1_2_,
        team1_.name as name2_2_ 
    from
        member member0_ 
    left outer join
        team team1_ 
            on member0_.team_id=team1_.team_id 
    where
        member0_.user_name=?

 

 

 

6. 정리


  • 프로젝션 대상이 root 엔티티면, JPQL SELECT 절 최적화 가능
  • 프로젝션 대상이 ROOT가 아니면
    • LEFT OUTER JOIN 처리
    • 모든 필드를 SELECT해서 엔티티로 조회한 다음에 계산
  • 프로젝션 대상이 root 엔티티면 유용하다.
  • 프로젝션 대상이 root 엔티티를 넘어가면 JPQL SELECT 최적화가 안된다!
  • 실무의 복잡한 쿼리를 해결하기에는 한계가 있다.
  • 실무에서는 단순할 때만 사용하고, 조금만 복잡해지면 QueryDSL을 사용하자

 

7. GitHub : 210831 Projection


 

GitHub - bsh6463/SpringDataJpa

Contribute to bsh6463/SpringDataJpa development by creating an account on GitHub.

github.com

 

'인프런 > [인프런] Spring Data JPA' 카테고리의 다른 글

Native Query  (0) 2021.09.01
Query By Example  (0) 2021.08.31
SpringDataJpa의 구현체  (0) 2021.08.31
Web 확장 : 도메인 클래스 컨버터, 페이징 & 정렬  (0) 2021.08.31
Auditing  (0) 2021.08.30
Comments