스프링 데이터 JPA 8. Projection - KwangtaekJung/inflearn-spring-data-jpa-keesun GitHub Wiki

스프링 데이터 JPA: Projection

엔티티의 일부 데이터만 가져오기.

인터페이스 기반 프로젝션

  • Nested 프로젝션 가능.

  • Closed 프로젝션

    • 쿼리를 최적화 할 수 있다. 가져오려는 애트리뷰트가 뭔지 알고 있으니까.

    • Java 8의 디폴트 메소드를 사용해서 연산을 할 수 있다.

    • Comment로 조회하면 모든 컬럼을 가져온다.

      List<Comment> findByPost_Id(Long id);  //연관 관계인 Post의 Id로 조회 (Comment 테이블 만들때 post_id 컬럼으로 만들어 지기때문에 findByPost로는 하면 에러 발생함.)
      select
          comment0_.id as id1_1_,
          comment0_.best as best2_1_,
          comment0_.comment as comment3_1_,
          comment0_.down as down4_1_,
          comment0_.post_id as post_id6_1_,
          comment0_.up as up5_1_ 
      from
          comment comment0_ 
      left outer join
          post post1_ 
              on comment0_.post_id=post1_.id 
      where
          post1_.id=?
    
    • 특정 컬럼만 가져온다. 쿼리 최적화한다.
    public interface CommentSummary {
    
      String getComment();
    
      int getUp();
    
      int getDown();
    }
      List<CommentSummary> findByPost_Id(Long id);
      select
          comment0_.comment as col_0_0_,
          comment0_.up as col_1_0_,
          comment0_.down as col_2_0_ 
      from
          comment comment0_ 
      left outer join
          post post1_ 
              on comment0_.post_id=post1_.id 
      where
          post1_.id=?
    
    • 쿼리 최적화도 같이 하는 방법 (default 메소드 이용한다.)
    public interface CommentSummary {
    
      String getComment();
    
      int getUp();
    
      int getDown();
    
      default String getVotes() {
          return getUp() + " " + getDown();
      }
    }
  • Open 프로젝션

    • @Value(SpEL)을 사용해서 연산을 할 수 있다. 스프링 빈의 메소드도 호출 가능.
    • 쿼리 최적화를 할 수 없다. SpEL을 엔티티 대상으로 사용하기 때문에.
    public interface CommentSummary {
    
      String getComment();
    
      int getUp();
    
      int getDown();
    
      @Value("#{target.up + ' '  + target.down}")
      String getVotes();
    }
      @Test
      public void getComment() {
          Post post = new Post();
          post.setTitle("jpa");
          Post savedPost = postRepository.save(post);
    
          Comment comment = new Comment();
          comment.setPost(savedPost);
          comment.setUp(10);
          comment.setDown(1);
          Comment savedComment = commentRepository.save(comment);
    
          commentRepository.findByPost_Id(savedPost.getId()).forEach(c -> {
              System.out.println("================");
              System.out.println(c.getVotes());
          });
      }
      select
          comment0_.id as id1_1_,
          comment0_.best as best2_1_,
          comment0_.comment as comment3_1_,
          comment0_.down as down4_1_,
          comment0_.post_id as post_id6_1_,
          comment0_.up as up5_1_ 
      from
          comment comment0_ 
      left outer join
          post post1_ 
              on comment0_.post_id=post1_.id 
      where
          post1_.id=?
    

클래스 기반 프로젝션

  • 이것도 Open, Close 프로젝션 모두 있음.
  • DTO
  • 롬복 @Value로 코드 줄일 수 있음

다이나믹 프로젝션

  • 프로젝션 용 메소드 하나만 정의하고 실제 프로젝션 타입은 타입 인자로 전달하기.
    <T> List<T> findByPost_Id(Long id, Class<T> type);
public interface CommentOnly {

    String getComment();
}
    @Test
    public void getComment() {
        Post post = new Post();
        post.setTitle("jpa");
        Post savedPost = postRepository.save(post);

        Comment comment = new Comment();
        comment.setComment("Spring Data Jpa");
        comment.setPost(savedPost);
        comment.setUp(10);
        comment.setDown(1);
        Comment savedComment = commentRepository.save(comment);

        commentRepository.findByPost_Id(savedPost.getId(), CommentSummary.class).forEach(c -> {
            System.out.println("================");
            System.out.println(c.getVotes());
        });

        commentRepository.findByPost_Id(savedPost.getId(), CommentOnly.class).forEach(c -> {
            System.out.println("================");
            System.out.println(c.getComment());
        });
    }
⚠️ **GitHub.com Fallback** ⚠️