QueryDsl On절에 null 대신 사용할 수 있는 방법

Yukicow·2024년 2월 6일
0
post-custom-banner

QueryDsl On절에 null 사용

QueryDsl은 On절에 null을 허용하지 않는다.

Where절에서는 null값을 반환하면 조건이 빠지도록 되어 있어 동적으로 조건을 부여하기 수월하지만 On절은 해당 기능을 지원하지 않는다.

이러한 문제를 해결하기 위한 방법이 무엇이 있을까 고민하던 도중, 조건을 부여하되 항상 true인 값을 부여하면 되지 않을까 하는 생각이 들었다.

이러한 접근법은 성공적이었고 해당 내용을 공유해 보고자 한다.



null 대신 Expessions.TRUE

		query
            .select(review)
            .distinct()
            .from(review)
            .join(review.member, member).fetchJoin()
            .join(review.room, room).fetchJoin()
            .leftJoin(review.reviewImages, reviewImage)
            .where(
                review.place.id.eq(cond.getPlaceId()),
                roomIdEq(cond.getRoomId())
                cond.getHasPhoto() ? reviewImage.review.id.isNotNull() : null
            )
            .orderBy(reviewSort(cond))
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize() + 1)
            .fetch();

위는 필자가 기존에 사용하던 코드이다.

동적으로 조건 부여가 필요한 코드는 아니지만, 당장 쓸만한 코드가 이거 밖에 없었다..


위의 Where절을 보면 조건이 필요 없는 경우 null을 반환하여 조건이 추가되지 않도록 하고 있다.

On절에도 조건이 필요하지 않을 때 추가되지 않도록 하는 방법이 무엇이 있을지 고민하다 발견 한 방법은, 조건이 추가되지 않아야 하는 경우에 True값을 넣는 것이었다.

		query
            .select(review)
            .distinct()
            .from(review)
            .join(review.member, member).fetchJoin()
            .join(review.room, room).fetchJoin()
            .leftJoin(review.reviewImages, reviewImage)
            .on(
                cond.getHasPhoto() ? reviewImage.review.id.isNotNull() : Expressions.TRUE
            )
            .where(
                review.place.id.eq(cond.getPlaceId()),
                roomIdEq(cond.getRoomId())
            )
            .orderBy(reviewSort(cond))
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize() + 1)
            .fetch();

위 코드를 보면

cond.getHasPhoto() ? reviewImage.review.id.isNotNull() : null

해당 부분이 On절로 이동한 것을 볼 수 있다.

다만 On절에는 null이 허용되지 않기 때문에 조건에 부합하지 않는 경우 null이 아닌 true가 들어갈 수 있도록 Expressions.TRUE를 사용했다.


조금 더 가독성을 높이고 싶다면 Where절에 사용하는 것처럼 메소드를 만들어서 사용하는 방법도 있다.

		query
            .select(review)
            .distinct()
            .from(review)
            .join(review.member, member).fetchJoin()
            .join(review.room, room).fetchJoin()
            .leftJoin(review.reviewImages, reviewImage)
            .on(hasPhoto(cond))
            .where(
                review.place.id.eq(cond.getPlaceId()),
                roomIdEq(cond.getRoomId())
            )
            .orderBy(reviewSort(cond))
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize() + 1)
            .fetch();
      
      
 private BooleanExpression hasPhoto(SearchCond cond) {
 	return cond.getHasPhoto() ? reviewImage.review.id.isNotNull() : Expressions.TRUE
 }

실제로 발생하는 쿼리를 보면

On절의 조건이 참일 경우 : reviewImage.review.id.isNotNull()


조건이 False 경우 : Expressions.TRUE


On 조건절에 조건이 필요 없는 경우 True가 들어가는 것을 볼 수 있다. 이는 항상 참이 되기 때문에 쿼리에 아무 영향을 미치지 않는다.

이제 On절에서도 Where절과 비슷한 형태로 동적인 조건 추가가 가능해졌다.

또, QueryDsl에서 Where절에 모든 조건이 null이 되는 경우 에러가 발생하게 되는데, 그런 경우의 수가 발생할 수 있는 쿼리라면 위처럼 항상 참이되는 조건을 넣어 두면 그런 문제를 피할 수도 있을 것 같다.

profile
자료를 찾다 보면 사소한 부분에서 궁금한 부분이 생기도 한다. 똑같은 복붙식 블로그 때문에 시간만 낭비되고 시원하게 해결하지 못 하는 경우가 많았다. 그런 부분들까지 세세하게 고민하고 함께 해결해 나가고자 글을 작성한다. 혼자서 작성하는 블로그가 아닌 함께 만들어 가는 블로그이다. ( 지식 공유를 환영합니다. )
post-custom-banner

0개의 댓글