본문 바로가기
Spring/Querydsl

Querydsl 동적쿼리

코동이 2022. 2. 13.

동적쿼리 사용 2가지 방법


동적 쿼리 사용을 위해서는 2가지 방법이 있습니다.

 

  • BooleanBuilder
  • Where 다중 파라미터 사용

 

BooleanBuilder


where절에 BooleanBuilder를 넣는 방식입니다. and 혹은 or을 사용할 수 있습니다. 아래는 username과 age를 동적 쿼리로 조회합니다.

 

 

where 절의 핵심 코드는 아래와 같습니다.

 

...
.where(builder)
...

 

@Test
public void BooleanBuilderQuery() {
	String usernameParam = "member1";
	Integer ageParam = 10;
	List<Member> result = searchMember1(usernameParam, ageParam);
	Assertions.assertThat(result.size()).isEqualTo(1);
}

private List<Member> searchMember1(String usernameCond, Integer ageCond) {
	BooleanBuilder builder = new BooleanBuilder();
	if (usernameCond != null) {
		builder.and(member.username.eq(usernameCond));
	}
	if (ageCond != null) {
		builder.and(member.age.eq(ageCond));
	}
    
	return queryFactory
			.selectFrom(member)
			.where(builder)
			.fetch();
}

 

 

where절에는 username과 age 모두 검색조건에 들어가 있습니다.

 

 

age를 null로 바꾸고 쿼리문을 짜봅니다.

 

Integer ageParam = null;

 

위의 where 조건에는 age가 포함되어 있었으나, 이제 age가 포함되지 않습니다. 동적으로 null이므로 빠졌습니다.

 

 

참고로 방어코드를 짠다는 전제하에,  BooleanBuilder에 초기값을 넣을 수도 있습니다.

 

BooleanBuilder builder = new BooleanBuilder(member.username.eq(usernameCond));

 

 

Where 다중 파라미터 사용


운영에서는 첫번째 BooleanBuilder보다는 Where 다중 파라미터 사용이 굉장히 편리합니다. where에서 좀 더 직관적으로 코드를 짤 수 있고 재사용도 가능합니다.

 

BooleanExpression을 리턴하는 usernameEq(String usernameCond), ageEq(Integer ageCond) 메서드를 만들어서 이름과나이를 검사할 수 있습니다.

 

where 절의 핵심 코드는 아래와 같습니다.

 

...
.where(usernameEq(usernameCond), ageEq(ageCond))
...

 

전체 코드는 아래와 같습니다.

 

@Test
public void 동적쿼리_WhereParam() throws Exception {
	String usernameParam = "member1";
	Integer ageParam = 10;
	List<Member> result = searchMember2(usernameParam, ageParam);
	Assertions.assertThat(result.size()).isEqualTo(1);
}

private List<Member> searchMember2(String usernameCond, Integer ageCond) {
	return queryFactory
			.selectFrom(member)
			.where(usernameEq(usernameCond), ageEq(ageCond))
			.fetch();
}

private BooleanExpression usernameEq(String usernameCond) {
	return usernameCond != null ? member.username.eq(usernameCond) : null;
}

private BooleanExpression ageEq(Integer ageCond) {
	return ageCond != null ? member.age.eq(ageCond) : null;
}

 

Where 다중 파라미터 방식은 첫번째 방식 BooleanBuilder와 같은 JPQL 쿼리문이 동작합니다. 

 

 

만약, usernameEq와 ageEq를 한번에 사용하고 싶다면 다음처럼 allEq() 함수를 만들어서 합칠 수 있습니다. BooleanExpression을 and로 연결하여 반환합니다.

 

@Test
public void 동적쿼리_WhereParam() throws Exception {
	String usernameParam = "member1";
	Integer ageParam = 10;
	List<Member> result = searchMember2(usernameParam, ageParam);
	Assertions.assertThat(result.size()).isEqualTo(1);
}

private List<Member> searchMember2(String usernameCond, Integer ageCond) {
	return queryFactory
			.selectFrom(member)
			//.where(usernameEq(usernameCond), ageEq(ageCond))
            .where(allEq(usernameCond, ageCond)
			.fetch();
}

private BooleanExpression usernameEq(String usernameCond) {
	return usernameCond != null ? member.username.eq(usernameCond) : null;
}

private BooleanExpression ageEq(Integer ageCond) {
	return ageCond != null ? member.age.eq(ageCond) : null;
}

private BooleanExpression allEq(String usernameCond, Integer ageCond) {
	return usernameEq(usernameCond).and(ageEq(ageCond)); 
}

 

BooleanExpression이 composite할 수 있는 특징을 이용해서 여러상황을 만들 수 있고, 재사용이 가능합니다. 예를들어 광고 아이디와 날짜를 이용해 광고 가능한 상태인가를 판단하는 문법을 다음과 같이 만들 수 있습니다.

 

//핵심코드
...
where(isServiceable(id, date))
...

private BooleanExpressions isServiceable(Integer id, String date) {
	return isValid(id).and(DateBetweenIn(date);
}

 

 

동적쿼리를 검사할 때, 간단할 때 3항연산자를 쓰지만, if문으로 만들 수도 있습니다.

 

//삼항 연산자
private BooleanExpression usernameEq(String usernameCond) {
	return usernameCond != null ? member.username.eq(usernameCond) : null;
}


//if,else
private BooleanExpression usernameEq(String usernameCond) {
	if(usernameCond == null) return null;
    
	return member.username.eq(usernameCond);
}

 

 

1,2번 방식을 비교해보겠습니다.

 

 

//1. BooleanBuilder
.where(builder);

//2. where 다중 파라미터 사용
.where(usernameEq(usernameCond), ageEq(ageCond));

 

BooleanBuilder 보다는 확실히 Where 다중 파라미터 사용이 where문을 봤을 때 좀 더 직관적으로 이해 할 수 있습니다. 또한 where 다중 파라미터 사용을 한다면 메서드들을 재활용할 수 있습니다.

 

물론, 동적쿼리인만큼 항상 null 체크에 주의해야 합니다.

 

 

* 출처

Inflearn : 실전! Querydsl 강의

 
반응형

'Spring > Querydsl' 카테고리의 다른 글

순수 JPA와 Querydsl  (0) 2022.02.13
QueryDsl 수정, 삭제  (0) 2022.02.13
QueryDsl 프로젝션 문법  (0) 2022.02.13
QueryDsl 기본문법  (0) 2022.02.12
JPA & JPQL & QueryDsl  (0) 2022.02.12