우리는 DB를 병목 지점으로 두고 싶지 않습니다.
그래서 데이터 조회는 필요한 컬럼만 작성하는 것이 바람직할 수 있습니다. 다만 ORM을 사용하면서 작업을 늘리기 싫은 경우, 부분 컬럼 조회에 대한 원칙 없이 사용하는 경우도 많습니다. 사실 적절한 선에서 타협해서 몇 가지 조회 모델만 만들어 놓고, 이걸 최대한 범용적으로 활용하는 정도가 나을 수도 있습니다.
단건 조회는 엔티티를 통째로 써도 일반적으로 (성능에는) 영향이 크지 않다고 평가할 수도 있지만, 목록 조회는 어느 정도 영향을 감안은 해서 (페이지네이션을 하더라도) 필요한 컬럼만 조회하고 싶을 수 있습니다.
그 외에도 단건 조회에서도 특정 컬럼 한두 개만 빈번하게 조회가 이루어지거나 하면 아무래도 신경이 쓰이는 영역이 될 수 있습니다. 우리는 어쨌든 DB를 병목 지점으로 두고 싶지 않기 때문입니다.
public interface MyProjection {
// 대표적인 Getter 네이밍으로 작성
String getName();
Integer getAge();
}
컬럼 두어 개만 적으니 생각보다 작성이 간편해 보입니다.
다만 컬럼이 서너 개씩만 돼도, 매번 Getter 양식을 준수하며 작성하는 것이 조금은 귀찮을 게 보입니다.
(JPA Repository에서 일반적인 조회 양식대로 메서드를 명명해서 사용하면 됩니다.)
public interface MyRepository extends JpaRepository<MemberProfileEntity, Long> {
List<MyProjection> findNameAndAgeByEmail(String email);
Page<MyProjection> findNameAndAgeByEmail(String email, Pageable pageable);
}
record는 데이터를 표현하는 목적에 비교적 충실한 클래스 유형 중 하나로, 모든 속성에 불변성을 보장해 줍니다.
그리고 스프링 부트 진영의 많은 기술은 이 record에 대한 호환성을 가져가는 경우가 꽤 많습니다. 그러니까 호기심이 들면 테스트해 보시면 되는 게 꽤 많습니다.
(map struct나 이 projection처럼요!)
public record MyProjection(String name, Integer age) {
}
완성입니다. 이제 인터페이스 대신 이 레코드를 쓰면 됩니다.
눈으로 보면 인터페이스도 비교적 간결해 보이는데, 조금 더 짧아진 이 record가 훨씬 편한 이유에는 단순 copy & paste로 작업이 끝나기 때문도 있는 듯합니다. record를 사용할 때는 따로 getter 양식으로 변환하지 않아도 되기 때문에 작업이 생각보다 많이 편해질 겁니다.
저는 보통 엔티티 클래스를 열어서 필요한 컬럼들만 다중 선택으로 복사해 프로젝션의 속성으로 넣고 있습니다.
붙여 넣은 후 휠 버튼 클릭&드래그로 커서를 여러 개 만들고 콤마 한 번만 찍으면 완료되는 작업을 생각해 보세요.
작성이 편한 만큼, 원한다면 부분 조회를 조금 더 습관화하기에도 유리합니다.