Springboot

Spring Data JPA의 @Query + DTO 생성자 방식

devfinger 2025. 11. 4. 13:46

findEmployeeSummariesByDepartment에서 “EmployeeSummary”는 반환할 DTO 클래스 이름을 JPQL 안에서 명시적으로 써야 한다는 점

✅ 1. DTO 생성자 기반 쿼리의 핵심 규칙

 
@Query("SELECT new com.example.dto.EmployeeSummary(e.name, e.salary) FROM Employee e WHERE e.department = :dept") List<EmployeeSummary> findEmployeeSummariesByDepartment(@Param("dept") String dept);

위 JPQL에서 new com.example.dto.EmployeeSummary(...) 부분이 중요합니다.

  • com.example.dto.EmployeeSummary → DTO 클래스의 전체 패키지 경로를 반드시 지정해야 합니다.
    (import 구문과 달리, JPQL은 패키지를 인식하지 못하므로 풀네임 필요)
  • 괄호 안의 e.name, e.salary → Employee 엔티티의 필드 이름입니다.
  • EmployeeSummary 클래스에는 그 순서와 타입이 일치하는 생성자가 반드시 있어야 합니다.

✅ 2. DTO 클래스 예시

 
package com.example.dto; public class EmployeeSummary { private final String name; private final int salary; public EmployeeSummary(String name, int salary) { this.name = name; this.salary = salary; } // getter는 선택적 (record로 써도 가능) public String getName() { return name; } public int getSalary() { return salary; } }

👉 JPA가 SQL을 실행할 때, name과 salary만 SELECT 하고
그 결과를 new EmployeeSummary(name, salary) 형태로 DTO에 매핑합니다.


✅ 3. 요약하자면

항목설명
findEmployeeSummariesByDepartment 단순히 메서드 이름일 뿐, EmployeeSummary 클래스명과 무관
new com.example.dto.EmployeeSummary(...) JPQL에서 DTO로 매핑하기 위한 생성자 호출 문법
e.name, e.salary Employee 엔티티의 필드 이름
DTO 클래스 생성자 파라미터가 쿼리 SELECT 항목과 정확히 일치해야 함

✅ 4. 자동 필드 매핑이 필요한 경우

만약 "쿼리에서 DTO 생성자 쓰기 너무 귀찮다"면,
다음처럼 Interface Projection을 쓰면 됩니다.

 
public interface EmployeeSummary { String getName(); int getSalary(); } public interface EmployeeRepository extends JpaRepository<Employee, Long> { List<EmployeeSummary> findByDepartment(String department); }

→ 이 경우에는 @Query 없이도 Spring Data JPA가
자동으로 SELECT name, salary FROM employee WHERE department = ? 형태의 쿼리를 만들어 줍니다.


즉,

  • DTO 생성자 방식 → 쿼리 안에서 new DTO(...) 직접 써야 함
  • Interface Projection 방식 → 쿼리를 안 써도, 메서드명 기반으로 필요한 필드만 자동 조회 가능