JPA 쓰다보면 어려운 것도 아닌데 헷갈리는 것들이 있다..
복잡한 쿼리는 아닌데, paging 이랑 group by 동시에 써야 되서 native query 가 더 깔끔한 거 같아서 native query 사용했는데 조건에 enum 값에 있는 것들로 in 절에 넣어야됐다.
물론 그냥 따옴표 안에 'ENUM.CODE_A, ENUM.CODE_B'
이렇게 넣어주면 편하지만
이건 개발하는 입장에서 맘이 편하지 않으니까 패스..
Native Query 에서 Enum 사용시 문제
그래서 @Param("keys") List<EnumCode> keys
를 넣어
@Query(value = "" +
"SELECT a.* " +
"FROM user a " +
"WHERE a.id = :userId AND a.remove = 0 " +
"AND a.key IN (:keys) " +
"GROUP BY a.create_at " +
"ORDER BY a.create_at DESC",
countQuery = "" +
"SELECT COUNT(a.id) FROM user a " +
"WHERE a.id = :userId AND a.remove = 0 " +
"AND a.key IN (:keys) " +
"GROUP BY a.create_at ",
nativeQuery = true)
Page<User> getUserDataGroupByCreatedAtByKey(@Param(value = "userId") Long id, @Param("keys")List<EnumCode> keys, Pageable pageable);
이렇게 했는데 콘솔에 찍어보니
AND a.key IN (
'ACED00057E72002F636F6D2E636865636B75702E776F726B73706163652E656E756D732E576F726B7370616365557365724C6F674B657900000000000000001200007872000E6A6176612E6C616E672E456E756D0000000000000000120000787074001D574F524B53504143455F555345525F4143544956455F555345525F4944'
, 'ACED00057E72002F636F6D2E636865636B75702E776F726B73706163652E656E756D732E576F726B7370616365557365724C6F674B657900000000000000001200007872000E6A6176612E6C616E672E456E756D0000000000000000120000787074001F574F524B53504143455F555345525F494E4143544956455F555345525F4944'
)
이렇게 찍혔다. 찾아보니
JPA에서 Enum 타입은 기본적으로 두 가지 방식(EnumType.ORDINAL 또는 EnumType.STRING)으로 데이터베이스에 저장될 수 있습니다. EnumType.ORDINAL은 Enum 값이 그 순서대로 데이터베이스에 숫자로 저장되는 것을 의미하고, EnumType.STRING은 Enum의 이름을 문자열로 저장하는 것을 의미합니다. 그러나, native query에서 이런 형태로 Enum 리스트를 사용할 경우, JPA의 자동 변환 기능에 의존할 수 없습니다.
즉, @Enumerated 어노테이션이 있더라도 native query에서는 이 설정이 적용되지 않아, Enum의 순서 값(ordinal)이 아닌 Enum의 이름을 원하는 경우에도 숫자 값으로 취급될 수 있습니다. 이는 JPA가 native query를 데이터베이스에 직접 전달하기 때문에, JPA의 Enum 처리 방식이 적용되지 않기 때문입니다.
그래서 고민했는데 생각해보니까 쉬운 문제였음 ㅎㅎ
해결 방안
List<String> keys = enumCodes.stream()
.map(Enum::name)
.collect(Collectors.toList());
@Query(value = "" +
"SELECT a.* " +
"FROM user a " +
"WHERE a.id = :userId AND a.remove = 0 " +
"AND a.key IN (:keys) " +
"GROUP BY a.create_at " +
"ORDER BY a.create_at DESC",
countQuery = "" +
"SELECT COUNT(a.id) FROM user a " +
"WHERE a.id = :userId AND a.remove = 0 " +
"AND a.key IN (:keys) " +
"GROUP BY a.create_at ",
nativeQuery = true)
Page<User> getUserDataGroupByCreatedAtByKey(@Param(value = "userId") Long id, @Param(value = "keys")List<String> keys, Pageable pageable);
완성 ^_^
이렇게 쉬운 걸..
String inClause = keys.stream()
.map(key -> "'" + key.name() + "'")
.collect(Collectors.joining(", "));
이런 식으로 삽질을 좀 해서 블로그에 정리해봤다.