JPA

[Jpa] Projections

kkkkkkkkkkkk 2022. 7. 18. 18:05

아래와 같은 엔티티의 조회 시도를 하려고 한다. select 문을 날리면 해당 엔티티의 속성들이 모두 조회가 될 것이다.

 

속성들이 이보다 더 많다면 아마 성능에 문제가 되지 않을까 싶다.

그래서 해당 속성만 뽑아내려고 시도 해봤다.

public class Post {

    private Long id;
    private String userName;
    private String title;
    private String description;
    private LocalDateTime createDateTime;
    private LocalDateTime updateDateTime;
}

 

당연히 받는 타입은 PostDto로 title 과 description 만 받게 해 놓았다.

@Query("select p.title, p.description " +
        "from Post p " +
        "where p.userName =:userName")
List<PostDto> findByName(@Param("userName") String userName);

 

 

데이터가 mapping이 제대로 되지 않아 아래와 같은 에러가 발생한다.

 

상속한 JpaRepository의 제네릭 타입인 Post 타입에 대한 mapping이 되어야 한다.

 

에러를 찾아 본 결과 jpa projections 으로 해결을 해야했다.

 

참조 : https://www.baeldung.com/spring-data-jpa-projections

 

Spring Data JPA Projections | Baeldung

A quick and practical overview of Spring Data JPA Projections.

www.baeldung.com

 

dto 클래스 활용

jpql 을 작성할 때 해당 dto의 new 인스턴스를 사용하여 쿼리를 동작하게 한다.

@Query("select new " +
        "com.study.boardsystem.web.dto.PostDto(p.title, p.description) " +
        "from Post p " +
        "where p.userName =:userName")
List<PostView> findByName(@Param("userName") String userName);

이때 해당 dto 의 생성자를 사용하여 mapping을 한다. 생성자의 매개변수 이름이 루트 엔티티 클래스의 속성과 일치해야 한다.

 

인터페이스 활용

루트 엔티티 속성의 getter 메서드 명과 같게 생성한다.

public interface PostView {
    public String getTitle();
    public String getDescription();
}

다음으로 jpql 을 작성한다. alias로 루트 엔티티와 mapping 되는 정보를 명시 해줘야 한다.

@Query("select p.title as title, p.description as description " +
        "from Post p " +
        "where p.userName =:userName")
List<PostView> findByName(@Param("userName") String userName);

런타임에 PostView 타입의 프록시 인스턴스를 생성하고 여기에 정의된 메서드를 호출하여 실제 타겟 객체에 전파하게 된다.

 

참조: https://realrain.net/post/spring-projection/

 

Spring Data JPA Projections

입사 후 당장 리소스가 필요한 부분이 프론트엔드 작업이었기에 작년에는 주로 자바스크립트와 리액트를 이용한 프론트 개발을 주로 했지만, 얼마 전부터 드디어 스프링 부트를 통해 서버개발

realrain.net

 

인터페이스는 Projection을 할 때에만 사용하고 dto 클래스는 언제든 데이터를 옮길 때 사용가능 하니 dto 클래스를 사용하여 인스턴스를 생성하는 것이 좋을 것 같다라는 생각이 든다.