Projections

  • 데이터베이스에서 테이블의 필요한 속성만을 조회하는 것을 말한다.
  • 불필요한 컬럼을 조회하는 것을 피함으로써 최적화된 쿼리를 설계할 수 있다.

인터페이스 기반 Projections

public interface ReplyCountInfo {

    Long getParentId();

    Integer getReplyCount();
}
  • 조회를 원하는 컬럼에 대해 get + 컬럼명와 같이 함수를 만들어주면 된다.
  • 쿼리를 구성할 때 as 별칭을 사용하여 인터페이스와의 컬럼명을 맞춰줘야 매핑이 잘 진행된다.
  • 재귀적으로도 Projections 할 수 있다.
interface PersonSummary {

  String getFirstname();
  String getLastname();
  AddressSummary getAddress();

  interface AddressSummary {
    String getCity();
  }
}

 

Closed Interface Projections

  • 닫힌 프로젝션은 지정한 컬럼만을 프로젝션하는 것을 말한다.
  • 지정한 컬럼만 가져오면 되므로 I/O 비용이 감소한다.

Open Interface Projections : 성능 최적화 이점이 없으므로 설명 생략

 

동작 방식

  • ProjectionFactory가 엔티티 클래스를 가져와 프로젝션 인터페이스의 동적 프록시 인터페이스 생성.
  • 메소드를 호출하면 동적 프록시의 InvocationHandler가 해당 호출을 가로채서 원본 엔티티에서 해당 속성 값을 찾아서 반환.
// 인터페이스 정의
interface UserInfo {
    String getName();
    String getEmail();
}

// 프록시 객체 (런타임 생성)
class UserInfoProxy implements UserInfo {
    Map<String, Object> columnIndexMap = {
    "name"   → "~",  // 실제 DB 컬럼명이 아닌 별칭 기준
    "email" → "~"
};

    public String getName() {
        return (String) columnIndexMap.get("name");  // 쿼리 결과의 첫 번째 컬럼
    }

    public String getEmail() {
        return (String) columnIndexMap.get("email");  // 두 번째 컬럼
    }
}

 

실제 적용

상황 : 게시글의 댓글을 조회할 때 부모 댓글말 조회하고, 대댓글의 경우 개수만 조회하여 댓글 밑에 ~~개 댓글 더보기와 같은 형식을 하려고 한다.

 

문제 : 부모 댓글에 대해 자식 댓글의 개수를 사용해야 하므로 group by와 count를 사용해야 했다. 이 때 count에 대한 정보는 Entity에 없으므로 매핑이 되지 않는다.

 

예제

@Query("""
            SELECT c.parent.id as parentId, count(c) as replyCount
            FROM StudyComment c
            WHERE c.parent.id in ?1
            GROUP BY c.parent.id
            """
)
List<ReplyCountInfo> countByParentIdListGroupByParentId(List<Long> parentIdList);

'Spring Boot > JPA' 카테고리의 다른 글

@Transactional 주의 사항  (0) 2025.02.18
@Transactional(readOnly = true) 이점  (0) 2025.02.18
Page 객체 응답 시 직렬화 변경 사항  (0) 2024.12.04
임베디드 타입 in JPA  (0) 2024.10.22
entity 기본 생성자 in jpa  (0) 2024.10.11

+ Recent posts