🧐 JPA 기반 프로젝트에서 UNION 쓰기
오늘 개발을 하다가 UNION을 사용할 일이 있었다.
처음에는 UNION을 해야하는 쿼리에 대해 각각 JPA가 지원하는 메소드를 통해 조회를 하고 그것을 합쳐서 자바의 Set 자료형으로 중복을 제거하려고 했다. 그런데, 이건 불필요한 중복 데이터를 어플리케이션 단까지 가져와야하는 작업이기에 나는 데이터베이스 내부에서 중복을 걸러주는 작업을 하는 것이 더 낫다고 판단해서 직접 UNION을 쓰려고 했다.
그래서 여느 때처럼 Querydsl을 사용해서 UNION을 구현하려고 하였더니 이게 웬걸.. Querydsl을 UNION을 지원하지 않았고, 그 이유는 Querydsl은 결국 JPQL을 자바로 코딩할 수 있는 정도만 지원하기 때문인데 JPQL 이 UNION을 지원하지 않기 때문이었다.
결국 나는 최후의 방법으로 네이티브 쿼리를 이용하여 쿼리를 직접 작성했다. 이 과정에서 작성하는 문자열이 실제 쿼리이기 때문에 WHERE 절이나 SELECT절 등 특정 구문이 끝나면 항상 띄어쓰기 즉, 공백(" ") 을 두어야 쿼리가 정상적으로 작동함을 알 수 있었다. 공백(" ")을 넣지 않으면 실제로 쿼리는 "WHERE CATEGORY=:IN_CATEGORYUNION" 이런식으로 CATEGORY와 UNION이 하나의 문자열이 되어버려 제대로 쿼리를 인식하지 못하는 불상사가 발생해버린다.
다음은 내가 짠 쿼리문이다. (내용 맥락 자체는 조금 변경해서 넣었기때문에 문법만 봐주시면 감사하겠습니다 ㅎㅎ)
@Query(value = "SELECT * FROM BOARDS "+
"WHERE CATEGORY=:IN_CATEGORY "+ // 항상 구문 끝날때마다 공백 넣어줘야함
"UNION "+
"SELECT * FROM BOARDS "+
"WHERE USER_ID=:IN_USER_ID "+
"ORDER BY CATEGORY DESC",
nativeQuery = true
)
List<Board> findAllDistinctByCategoryAndUserId(@Param("IN_CATEGORY") String category, @Param("IN_USER_ID") String userId);
추가로, 현재는 String으로 Category를 받고 있는 걸 알 수가 있는데, 나 같은 경우는 원래 Category가 Enum 상수로 정의를 해놨기 때문에 서비스단에서 파라미터를 넘겨줄 때, Enum 상수의 문자열 값을 받도록 (Category.상수.getValue()) 이런식으로 넘겨주었다. (기존에 Enum to 문자열로 만드는 Converter도 만들었지만 네이티브쿼리에서는 동작하지않는다.)
🧐 네이티브 쿼리에 Enum 적용하기
그런데 문득,
"굳이 내가 서비스단에서 Enum 상수를 문자열로 변경하는 것이 아니라 그냥 Enum 상수를 넘기면 알아서 네이티브쿼리가 문자열로 변환해주는 건 없을까" 라는 궁금증이 생겼다
구글링을 통해 찾아보니, SpEL (Spring Expression Language) 표현식을 통해 구현할 수 있는 방법이 있었다.
🧐 SpEL (Spring Expression Language)이란?
- 스프링 프로젝트에서 런타임에 쿼리를 지원하여 객체를 조작할 수 있는 표현식을 뜻한다.
SpEL을 사용해서 Native Query에서 Enum 타입 사용하기
Enum의 변수를 파라미터로 넘길 때는 바인딩되는 파라미터를 다음과 같이 작성하면 된다.
#{#파라미터 변수.name()} 혹은 #{#파라미터 변수.사용자가 작성한 getter}
적용한 쿼리와 코드는 다음과 같다.
@Query(value = "SELECT * FROM BOARDS "+
"WHERE CATEGORY=:#{#IN_CATEGORY.getValue()} "+ // 나는 enum 클래스에 getValue() 라는 getter을 작성해두어서 getValue()를 사용했다.
"UNION "+
"SELECT * FROM BOARDS "+
"WHERE USER_ID=:IN_USER_ID "+
"ORDER BY CATEGORY DESC",
nativeQuery = true
)
List<Board> findAllDistinctByCategoryAndUserId(@Param("IN_CATEGORY") Category category, @Param("IN_USER_ID") String userId);
코드를 보면 실제로 String 타입으로 넘겨주던 category가 Category 라는 enum 타입으로 넘겨주고 있음을 알 수 있다.
📘 Ref.
https://withseungryu.tistory.com/160
[JPA] native query 사용 시 enum을 변수로 하기 ( SpEL expression )
🙂 Native Query 란? JPQL을 사용해서 쿼리 메소드를 사용하는 것이 아닌 MySQL과 비슷한 형식으로 쿼리를 만들어 적용할 수 있다. 그러나, JPQL에서는 표준 SQL의 대부분의 기능을 지원하지만, 지원하지
withseungryu.tistory.com
Union 사용이 가능할까요?? - 인프런
안녕하세요. 강의 잘 듣고 있습니다. 강의 내용 중에 Union에 대한 내용을 아직 확인하지 못했습니다. (혹시 있었다면 죄송합니다;; ) 혹시 Querydsl 기반으로 Union 사용이 가능할까요?? 구글링을 해보
www.inflearn.com
'개발기록(feat.삽질)' 카테고리의 다른 글
| [Querydsl] java.time.LocalDateTime is not compatible with java.lang.String 에러 (0) | 2024.10.23 |
|---|---|
| Jackson사용 시 primitive boolean주의점 (0) | 2024.08.19 |
| git add, commit, push (0) | 2024.07.09 |
| @JsonCreater : Enum Type Request Dto Mapping (0) | 2024.07.09 |
| JPA Auditing과 Querydsl (0) | 2024.07.08 |