@Test
public void 동적쿼리_BooleanBuilder() throws Exception {
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();
}
@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 조건에 null 값은 무시된다.
🎈메서드를 다른 쿼리에서도 재활용 할 수 있다.
쿼리 자체의 가독성이 높아진다.
조합 가능
private BooleanExpression allEq(String usernameCond, Integer ageCond) {
return usernameEq(usernameCond).and(ageEq(ageCond));
}
null 체크는 주의해서 처리해야함
Predicate
와 BooleanExpression
은 QueryDSL에서 사용되는 조건 표현을 나타내는 인터페이스입니다.
Predicate 보다는 BooleanExpression 을 사용하는 이유로는 BooleanExpression 은 and 와 or 같은 메소드들을 이용해서 BooleanExpression 을 조합해서 새로운 BooleanExpression 을 만들 수 있다는 장점이 있다. 그러므로 재사용성이 높다. 그리고 BooleanExpression 은 null 을 반환하게 되면 Where 절에서 조건이 무시되기 때문에 안전하다.
long count = queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute();
기존 숫자에 1 더하기
long count = queryFactory
.update(member)
.set(member.age, member.age.add(1))
.execute();
곱하기: multiply(x)
쿼리 한번으로 대량 데이터 삭제
long count = queryFactory
.delete(member)
.where(member.age.gt(18))
.execute();
주의: JPQL 배치와 마찬가지로, 영속성 컨텍스트에 있는 엔티티를 무시하고 데이터베이스에 직접 실행되기 때문에 배치 쿼리를 실행하고 나면 영속성컨텍스트와 데이터베이스가 동기화 되지 않는다. 따라서 영속성 컨텍스트를 초기화 하는 것이 안전하다.
@PersistenceContext
EntityManager em;
long count = queryFactory
.delete(member)
.where(member.age.gt(18))
.execute();
em.clear(); // 영속성 컨텍스트를 초기화하여 삭제된 회원들을 제거
SQL function은 JPA와 같이 Dialect에 등록된 내용만 호출할 수 있다.
member M으로 변경하는 replace 함수 사용
String result = queryFactory
.select(Expressions.stringTemplate("function('replace', {0}, {1},{2})", member.username, "member", "M"))
.from(member)
.fetchFirst();
소문자로 변경해서 비교해라.
.select(member.username)
.from(member)
.where(member.username.eq(Expressions.stringTemplate("function('lower', {0})",member.username)))
lower 같은 ansi 표준 함수들은 querydsl이 상당부분 내장하고 있다. 따라서 다음과 같이 처리해도 결과 는 같다.
.where(member.username.eq(member.username.lower()))
참고
김영한 QueryDsl 강의 자료