Projection
데이터베이스에서 필요한 속성만 조회하는 것을 projection 이라고 한다.
예를 들면 필드 하나만 조회하거나 DTO로 조회를 하는 경우를 뜻한다.
Spring Data JPA는 projection 기능을 어떻게 할까?
1. 인터페이스 기반 - 조회하고 싶은 필드를 getter 형식으로 지정
public interface UsernameOnly {
String getUsername();
}
public interface MemberRepository ... {
List<UsernameOnly> findProjectionsByUsername(String username);
}
메서드 이름은 자유롭게 지정해도 되며, Spring Data JPA는 반환 타입을 보고 인지한다.
public interface NestedClosedProjection {
String getUsername();
TeamInfo getTeam();
interface TeamInfo {
String getName();
}
}
인터페이스 기반 - 중첩구조를 사용해 속성 하위 집합 처리 가능하다.
하지만 이 경우 team은 루트 엔티티가 아니므로 LEFT OUTER JOIN을 사용하고, 모든 필드를 SELECT해서 엔티티로 조회한 다음에 계산하므로 최적화가 안된다.
select
m.username as col_0_0_,
t.teamid as col_1_0_,
t.teamid as teamid1_2_,
t.name as name2_2_
from
member m
left outer join
team t
on m.teamid=t.teamid
where
m.username=?
Closed Projections
프로퍼티 형식(getter)의 인터페이스를 제공하면, 구현체는 스프링 데이터 JPA가 제공한다.
위 형식 인터페이스 기반 Closed Projections의 예이다.
이 경우 Spring Data JPA는 프록시를 지원하는 데 필요한 모든 속성을 알고있으므로 쿼리 실행을 최적화할 수 있다.
Open Projections
@Value(SpEL문법)를 사용해서 연산한다.
이렇게 하면 DB에서 엔티티 필드를 다 조회한 다음에 계산하므로 JPQL SELECT 절을 최적화할 수 없다.
또한 표현식은 너무 복잡해서는 안된다.
public interface UsernameOnly {
@Value("#{target.username + ' ' + target.age + ' ' + target.team.name}")
String getUsername();
}
2. 클래스 기반
위처럼 인터페이스가 아닌 구체적인 DTO 형식으로도 프로젝션이 가능하다.
이는 생성자의 파라미터 이름으로 매칭
인터페이스 기반 방식과 유사하지만 이는 중첩된 프로젝션을 적용할 수 없다.
public class UsernameOnlyDto {
private final String username;
public UsernameOnlyDto(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}
3. 동적 Projections - 제네릭 타입을 주면, 동적으로 프로젝션 데이터를 변경 가능하다.
<T> List<T> findProjectionsByUsername(String username, Class<T> type);
// 사용 예
List<UsernameOnly> result = memberRepository.findProjectionsByUsername("m1", UsernameOnly.class);
+ 스프링 데이터 JPA의 네이티브 쿼리와 인터페이스 기반 Projections 활용한 예
@Query(value = "SELECT m.member_id as id, m.username, t.name as teamName " +
"FROM member m left join team t ON m.team_id = t.team_id",
countQuery = "SELECT count(*) from member",
nativeQuery = true)
Page<MemberProjection> findByNativeProjection(Pageable pageable);
정리하면
프로젝션 대상이 root 엔티티면 JPQL SELECT절 최적화가 가능해 유용하게 사용할 수 있다.
하지만 root 엔티티가 아니라면 JPQL SELECT 최적화가 안된다.
따라서 단순할 때만 사용하는 것을 권장한다.
참고
실전! 스프링 데이터 JPA 강의 | 김영한 - 인프런
김영한 | 스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제
www.inflearn.com
Projections :: Spring Data JPA
Spring Data query methods usually return one or multiple instances of the aggregate root managed by the repository. However, it might sometimes be desirable to create projections based on certain attributes of those types. Spring Data allows modeling dedic
docs.spring.io
'JPA' 카테고리의 다른 글
[Querydsl] 적용 방법 (0) | 2024.12.30 |
---|---|
[Spring Data JPA] 새로운 엔티티 구별 방법 (0) | 2024.12.30 |
[Spring Data JPA] 도메인 클래스 컨버터 (0) | 2024.12.30 |
[Spring Data JPA] Auditing (0) | 2024.12.30 |
[Spring Data JPA] @EntityGraph (0) | 2024.12.30 |