JPQLQuery where문이 오늘 또..
JPQLQuery where
어제 querydsl의 where의 몇몇 코드들을 변경하거나 순서를 바꾸는 등 노력한 결과 여태까지 잘못쓰고 있었던 검색 기능을 정상적으로 고쳐놨지만, 이것은 내가 만든 커스텀 QuerydslRepositorySupport를 사용하고 있을 때의 경우이다.
구체적으로는 JPAQuery으로 쿼리를 구성하여 사용하였지만, 만약 급한 상황에서 새롭게 애플리케이션을 만들어야 하고 querydsl를 사용하는 상황에 기본 QuerydslRepositorySupport를 상속받아 사용해야 한다면 JPQLQuery으로 쿼리를 구성해야 하는데 혹시나 하는 마음에 기본 QuerydslRepositorySupport으로 교체해서 어제 고쳐 쓴 where 조건문을 입력하여 테스트를 해보았으나 어제와 같은 에러가 출력되었다.
신기하게 where의 조건을 추가할 때에 콤마(,)로 연결하여 쓰면 null이 무시되면서 잘 실행되지만 다른 연산자 and나 or를 사용했을 때는 첫번째 조건에서 리턴되는 값이 null이라면 어제와 같은nullpointerException에러가 나타나는데 이 현상을 검색을 하면서 이와 같은 에러 현상이 몇몇 있었지만 이 에러가 나타난 원인을 상세히 나온 것은 없었기에 결국 첫번째 조건에서 리턴되는 값이 절대 null이면 안되는 상황이었다.
생각해낸 해결방안
그래서 내가 생각해낸 해결방안은 BooleanExpression메서드들을 바꿔야 한다는 생각이었다.
일단 처음으로 애플리케이션을 실행하였을 때 어제와 같이 조건에 들어가는 검색조건과 키워드는 null이기에 BooleanExpression메서드들이 리턴되는 값은 모두 null이기에 모두가 리턴값이 null이라면 리턴값을 전체 게시물이 리턴되는 경우를 if문으로 추가하여 바꾼 결과 일단 에러가 없어지긴 하였다.
- 일부 BooleanExpression 변경한 코드
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
QBoard board = QBoard.board;
public class BoardSearchImpl extends QuerydslRepositorySupport implements BoardSearch {
public BoardSearchImpl(){
super(Board.class);
}
QBoard board = QBoard.board;
QReply reply = QReply.reply;
@Override
public Page<BoardOfReplyCountDTO> searchReplyCount(String[] types, String keyword, Pageable pageable){
JPQLQuery<Board> query = from(board)
.leftJoin(reply).on(reply.board.eq(board))
.groupBy(board)
.where(CheckAll(types,keyword)
);
JPQLQuery<BoardOfReplyCountDTO> dtoQuery = query.select(Projections.bean(BoardOfReplyCountDTO.class,
board.bno,
board.title,
board.user,
board.regDate,
reply.count().as("replyCount"))
);
this.getQuerydsl().applyPagination(pageable,dtoQuery);
List<BoardOfReplyCountDTO> list = dtoQuery.fetch();
Long count = dtoQuery.fetchCount();
return new PageImpl<>(list,pageable,count);
}
private BooleanExpression CheckAll(String[] types, String keyword){
BooleanExpression title = CheckTitle(types, keyword);
BooleanExpression content = CheckContent(types, keyword);
BooleanExpression user = CheckUser(types, keyword);
if(title == null && content == null && user == null){
return board.bno.gt(0L);
}else{
return 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 || types.length == 0){
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|| types.length == 0){
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 || types.length == 0){
return null;
}else{
return Arrays.asList(types).contains("u") == true ? board.user.contains(keyword) : null;
}
}
}
일단 해결되긴 했지만 CheckAll()메서드를 보면 위에 있는 BooleanExpression 메서드들이 모두 리턴값이 null인지 한번 실행되는데, 만약 검색조건과 키워드가 들어오면 앞서 과정을 한번 실행하고 마지막에 또 리턴값을 가져오기 위해 결국 두번 실행 되는 꼴이 되어버려 괜히 작업량을 늘리는게 아닌가 싶었다.
그렇다면 한번만 실행하기 위해서는 BooleanExpression의 리턴값을 기준으로 잡을 것이 아니라 검색조건과 키워드가 모두 null인지 확인하면 되지 않을까해서 if문 조건을 수정하고 다시 테스트를 돌려본 결과 정상적으로 검색기능이 작동하였다.
- 최종적으로 CheckAll() 메서드를 수정한 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private BooleanExpression CheckAll(String[] types, String keyword){
if((types == null ||types.length == 0 ) && keyword == null){
return board.bno.gt(0L);
}else{
return board.bno.gt(0L)
.and(CheckTitle(types,keyword)
.or(CheckContent(types,keyword))
.or(CheckUser(types, keyword)));
}
}