ConverterNotFoundException: No converter found capable of converting from type
문제 상황
@Query(nativeQuery = true,
value = "SELECT s.id, s.email, s.name " +
"FROM student s " +
"LEFT OUTER JOIN team t ON s.team_id = t.id " +
"WHERE now() BETWEEN t.start_date AND t.end_date " +
"AND t.category_id IN :categoryList " +
"AND t.is_public = :isPublic")
List<StudentDto> find(@Param("categoryList") List<Long> categoryList,
@Param("isPublic") Flag isPublic);
nativeQuery를 true로 놓고 쿼리를 날린 후 Dto로 받아오려고 했다.
쿼리를 날린 결과가 DTO에 매핑되지 않아서 즉, 결과를 객체로 변환하는 데에 실패해서 발생한 에러.
해결 및 개선
구글링을 통해 찾아본 해결 방법으로는 기존의 WrapperClass를 내가 필요한 것만 있는 interface로 정의하는 방법이 있었다.
public interface StudentDtoInterface {
Long getId();
String getName();
}
위는 예시 코드다.
나의 경우엔 실제로는 Dto에 넣어야할 데이터의 개수가 훨씬 많았고, 이런 식으로 인터페이스로 만들어서 하는 게 맞는지에 대해 의문이 들었다.
그래서 JPA를 사용한 다른 코드들의 로직을 생각해봤다.
JpaRepository에서 제공해주는 findAll()을 호출해서 List<Student>를 받아온 뒤,
서비스 계층에서 필요한 정보만 가져다가 Dto로 변환해서 응답으로 반환하는 형식으로 구현했다.
이 부분도 마찬가지로 우선 List<Student>를 받아온 다음에 서비스 계층에서 Dto로 변환하기로 했다.
@Query(value = "SELECT s " +
"FROM Student s " +
"LEFT JOIN s.team t " +
"WHERE current_timestamp BETWEEN t.startDate AND t.endDate " +
"AND t.category_id IN :category_id " +
"AND t.is_public = :isPublic")
List<Student> find(@Param("categoryList") List<Long> categoryList,
@Param("isPublic") Flag isPublic);
nativeQuery를 사용하지 않았다.
Repository에서는 이렇게 List<Student>로 받아온 뒤
서비스 계층에서 Dto로 변환해서 필요한 정보만 응답할 수 있도록 했다.
이렇게 하는 것이 다른 인터페이스를 추가하고 하는 것보다 더 JPA스럽다..?고 생각한다.
개인적으로는 꼭 필요한 상황이 아닌 이상 전자처럼 DTO로 바로 받아오는 방식으로 구현하려면
JPA, JPQL이 아니라 MyBatis로 개발하는 것이 더 좋아보인다.
이 글의 코드를 보다가 저 파라미터들을 한 번에 넘기고 싶다는 생각이 들었다면 아래 글을 봐주세요~
참고
'Spring' 카테고리의 다른 글
Spring에서 Feign 사용하기 (0) | 2023.07.31 |
---|---|
JPA JPQL 파라미터 객체(Object)로 한 번에 넘기기 (0) | 2023.07.26 |
JPA 양방향 매핑 Entity 한 번에 저장하기 (0) | 2023.07.23 |
Not a managed type: class java.lang.Object 에러 해결 (0) | 2023.07.23 |
'Basic' attribute type should not be a container 에러 해결 (0) | 2023.07.23 |