Spring Data JPA Dynamic Projections

Jong-Dae ParkJong-Dae Park
2 min read

1] 기존 Projections

특정한 Entity의 컬럼을 전부 가져오고 싶지 않을 때, 기존의 경우는 메서드마다 record를 생성하였다.

이때, 출처에서 적힌 것처럼, 여러 메서드가 하나의 record를 쓰는 경우가 생기게 된다.

예를 들어, 컬럼이 id, name, genre, 등등이 있을 때 기존에 id와 name만을 가져오는 record가 있을 경우 id, name, genre를 가져오는 메서드를 만들 경우 기존의 record에 genre 필드를 추가하여 동일한 record를 사용하는 실수가 생기게 된다.

2] Dynamic Projections

그래서 Spring Data JPA에서는 Dynamic Projections을 지원한다.
(Spring Data JPA 2.5.4 버전에서는 사용할 수 없는 것 같습니다. 3.2.6버전에서는 가능하네요)

1. Entity

@Getter
@Setter
@NoArgsConstructor
@Entity
@ToString
@Table(name = "MOVIE")
public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "MOVIE_TYPE_CD")
    private MovieType movieType;

    @Column(name = "NAME")
    private String name;
    @Column(name = "GENRE")
    private String genre;
}

2. Repository

public interface ProjectionRepository extends Repository<Movie, Long> {
    <T> T findById(Long id, Class<T> projection);
}

3. Record

record MovieInfo(Long id, String name) {}

4. 사용

var movieInfo = projectionRepository.findById(1L, MovieInfo.class);

3] Local Record를 이용한 Projections

메서드 안에 Record를 선언하여 이용하면 projection은 method 안에서만 사용되고 리턴되지 않는다.

또한 local class는 자신을 둘러싼 메서드의 지역 변수에 접근할 수 있으나, record는 그렇지 않다.

ex) Local Class VS Local Record

public void someMethod() {
    int outerVariable = 10;

    // 지역 레코드 클래스 (암묵적 정적)
    record LocalRecord(int x) {
        public void printOuterVariable() {
            // 컴파일 오류: outerVariable에 접근할 수 없음
            System.out.println(outerVariable); 
        }
    }

    // 지역 클래스 (정적 불가)
    class LocalClass {
        public void printOuterVariable() {
            System.out.println(outerVariable); // outerVariable에 접근 가능
        }
    }
}

따라서 다음과 같이 서비스에서 이렇게 사용할 수 있다.

public class SomeService {

    void someMethod() {
        record MovieInfo(Long id, String name) {}

        var memberInfo = projectionRepository.findById(1L, MovieInfo.class);
    }
}

실제 나가는 쿼리 검증

@Test
void showMovie() {
    record MovieInfo(Long id, String name) {}

    var memberInfo = projectionRepository.findById(1L, MovieInfo.class);
    System.out.println(memberInfo.toString());
}

로 테스트 해본 결과, 로그에서 의도대로 찍히는 것을 볼 수 있다.

4] 단점

  1. 메서드 호출시마다 record를 생성한다.

  2. 출처에서 적힌 것처럼, Spring Data JPA를 이용하므로, where 조건이 메서드명에만 존재한다.


References

https://maciejwalkowiak.com/blog/spring-data-jpa-dynamic-projections/

https://docs.spring.io/spring-data/jpa/reference/repositories/projections.html

https://docs.oracle.com/en/java/javase/17/language/records.html

출처에서 안 가져온 내용이 많으므로, 출처를 꼭 읽어보길 권장합니다.

0
Subscribe to my newsletter

Read articles from Jong-Dae Park directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jong-Dae Park
Jong-Dae Park