Querydsl 수업을 듣고 정리한 내용입니다.
🔔 동적 쿼리를 해결하는 두 가지 방식
BooleanBuilder
Where
다중 파라미터 사용
BooleanBuilder 사용
@Test
public void dynamicQuery_BooleanBuilder() throws Exception {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember1(usernameParam, ageParam);
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();
}
BooleanBuilder
를 통한 동적 쿼리 생성은 빌더를 생성 후 필요한 조건을 null
확인 여부에 따라 and
또는 or
등으로 더해주면 된다.
실행 결과
@Test
public void dynamicQuery_WhereParam() throws Exception {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember2(usernameParam, ageParam);
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;
}
where
조건에 null
값은 무시된다.usernameEq()
와 같은 메서드를 다른 쿼리에서도 재활용할 수도 있다.
실행 결과
✔️ 메서드 조합 가능
private BooleanExpression allEq(String usernameCond, Integer ageCond) {
return usernameEq(usernameCond).and(ageEq(ageCond));
}
method chaining
가능null
체크는 주의해서 처리해야 한다.
✔️ 쿼리 한 번으로 대량 데이터 수정
@Test
@Commit
public void bulkUpdate() {
// member1 = 10 -> DB member1
// member2 = 20 -> DB member2 // member3 = 30 -> DB member3 // member4 = 40 -> DB member4
long count = queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute(); // count : 용량을 받은 회원 수
// member1 = 10 -> DB 비회원
// member2 = 20 -> DB 비회원
// member3 = 30 -> DB member3
// member4 = 40 -> DB member4
List<Member> result = queryFactory
.selectFrom(member)
.fetch();
for (Member member1 : result) {
System.out.println("member1 = " + member1);
}
}
em.flush(), em.clear()
)
실행 결과
db
소스 실행
✔️ 기존 숫자에 1 더하기
@Test
public void bulkAdd() {
long count = queryFactory
.update(member)
.set(member.age, member.age.add(1))
.execute();
}
multiply(x)
실행 결과
✔️ 쿼리 한번으로 대량 데이터 삭제
@Test
public void builDelete() {
long count = queryFactory
.delete(member)
.where(member.age.gt(18))
.execute();
}
실행 결과
❌ 주의
JPQL 배치와 마찬가지로, 영속성 컨텍스트에 있는 엔티티를 무시하고 실행되기 때문에 배치 쿼리를 실행하고 나면 영속성 컨텍스트를 초기화 하는 것이 안전하다.
SQL function은 JPA와 같이 Dialect에 등록된 내용만 호출할 수 있다.
✔️ member → M으로 변경하는 replace 함수 사용
@Test
public void sqlFunction() {
List<String> result = queryFactory
.select(Expressions.stringTemplate(
"function('replace', {0}, {1}, {2})",
member.username, "member", "M"))
.from(member)
.fetch();
for (String s : result) {
System.out.println("s = " + s);
}
}
member
가 M
으로 변경된다.
실행 결과
✔️ lower 함수 - 소문자로 변경해서 비교
@Test
public void sqlFunction2() {
List<String> result = queryFactory
.select(member.username)
.from(member)
.where(member.username.eq(
Expressions.stringTemplate("function('lower', {0})", member.username)))
// .where(member.username.eq(member.username.lower()))
.fetch();
for (String s : result) {
System.out.println("s = " + s);
}
}
lower
같은 ansi
표준 함수들은 querydsl이 대부분 내장하고 있기 때문에 다음과 같이 처리해도 결과는 같다.
.where(member.username.eq(member.username.lower()))
실행 결과