Post

QueryDsl where 조건문 or이냐 and냐

QueryDsl where 조건문 or이냐 and냐

select from where

QueryDsl를 잘 사용하면 별도로 쿼리문을 일일히 입력해서 사용할 필요도 없고, 이러한 작업에서 쿼리문이 길어진다면 자잘한 오탈자만 발생하더라도 에러출력이 “오탈자가 생겨서 오류가 발생하였습니다”라는 단순히 나오는 것이 아니라 장문의 에러코드들이 출력되어 처음에는 오탈자가 원인이라는 것이 파악하지 못할 것이다.

그래서 지금까지 querydslRepositorysupportBooleanExpression 들을 적절히 조합해서 잘 사용하고 있었는데, 문득 잘 구현해낸 게시물 검색 기능이 지금까지 잘못 기능하고 있다는 것을 알게 되었다.


  • 검색 기능 10_10_search

구체적으로 보통 사이트에서 단순한 검색 기능도 있지만 이미지에 검색 왼쪽처럼 자신이 검색 조건을 선택하거나 다수의 검색 조건에서 특정 키워드를 같이 검색할 수 있게 기능을 구현을 해놓았다.
나도 비슷하게 구현하였는데 여태까지 잘 기능하고 있다고 생각했지만 다수의 검색 조건에서 하나의 조건에 부합되더라도 검색하는 기능이 제대로 구현되지 않았다.
정확히 검색 조건이 “제목”, “내용”, “작성자”가 있으면 처음 “제목”이라는 조건에 필터링되고 다음 조건인 “내용”,”작성자”의 조건들에서 검색 키워드가 일치하지 않으면 처음 조건에서 필터링된 게시물들이 제외되서 결과적으로 아무것도 검색되지 않게 되었다.


원인 파악 및 해결

그렇다면 QueryDsl에서 페이징 처리를 할 때 쿼리 조건(where)를 잘못 구성한 것 같아 where 조건문에서 사용하는 문법을 열심히 찾아본 결과 여태까지 where 조건들을 다수로 연결하였을 때 콤마(,)로 연결하였는데 여기서 콤마(,)는 연산자 and를 의미한다고 한다.

그래서 검색 키워드가 하나의 조건에 부합되지 않는다면 검색이 되지 않았던 것이다. 그래서 연산자 and가 원인이었으니 연산자 or로 대체하면 해결되겠다 싶어 바꿨지만 이번엔 검색 기능조차 되지 않았다.

cannot invoke "com.querydsl.core.types.dsl.booleanexpression.and...이런식으로 콘솔창에 에러가 장문으로 출력되었는데 아마 추측하기로는 처음 프로젝트 애플리케이션을 실행하면 검색키워드와 검색조건 값이 당연히 없기에 전체 게시물들을 가져와야겠지만 BooleanExpression에서는 앞서 값들을 null이라고 에러로 던져버린 것 같았다.
그렇다면 처음 QueryDslwhere조건을 구성할 때 검색 조건들에 앞서 게시물 번호가 0보다 큰 게시물들을 가져온다는 조건을 붙인다면 전체 데이터들을 먼저 가져오기에 위의 문제가 해결될 것 같아 where조건의 첫번째로 board.bno.gt(0L)를 입력하고 다음으로 검색 조건들을 추가하고 다시 실행해본 결과 제대로 기능을 하였다.

  • 개선한 일부 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
QBoard board = QBoard.board;

public Page<Board> searchAll(String[] types, String keyword, Pageable pageable){

        return applyPagination(pageable, query -> query.selectFrom(board)
                .where(board.bno.gt(0L)
                        .or(CheckTitle(types,keyword))
                        .or(CheckContent(types,keyword))
                        .or(CheckUser(types,keyword)))
        );
}

private BooleanExpression CheckTitle(String[] types, String keyword){
        if(types == null || keyword == null){
            return null;
        }else{
            return Arrays.asList(types).contains("t") == true ? board.title.contains(keyword) : null;
        }
    }

    private BooleanExpression CheckContent(String[] types, String keyword){
        if(types == null || keyword == null){
            return null;
        }else{
            return Arrays.asList(types).contains("c") == true ? board.content.contains(keyword) : null;
        }
    }

    private BooleanExpression CheckUser(String[] types, String keyword){
        if(types == null || keyword == null){
            return null;
        }else{
            return Arrays.asList(types).contains("u") == true ? board.user.contains(keyword) : null;
        }
    }        


This post is licensed under CC BY 4.0 by the author.