안녕하세요. J4J입니다.
이번 포스팅은 QueryDSL where절에 1=1 사용하는 방법에 대해 적어보는 시간을 가져보려고 합니다.
where절에 1=1 사용이 필요한 경우
QueryDSL에서 where절에 1=1 사용이 필요한 경우는 동적으로 사용되는 조건절에 대응하기 위해 주로 활용합니다.
이 부분은 QueryDSL뿐만 아니라 Native JPA나 Mybatis에서도 충분히 사용될 수 있는 요소입니다.
해당 상황을 알아보기 위해 다음과 같은 테이블 및 클래스 파일들이 있다고 가정해 보겠습니다.
// table
create table school (
no int primary key auto_increment,
name varchar(50),
address varchar(50)
)
// entity
package com.querydsl.oneequalone.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "school")
public class SchoolEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int no;
private String name;
private String address;
}
// request dto
package com.querydsl.oneequalone.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SchoolOneToOneSearch {
private int no;
private String address;
}
그리고 request의 파라미터로 넘어오는 SchoolOnetoOneSearch에 들어있는 모든 요소들에 no나 address가 하나라도 일치한 것이 존재하는 데이터들만 조회되게 만들려고 합니다.
그럴 경우 다음과 같은 QueryDSL이 작성될 수 있습니다.
package com.querydsl.oneequalone.repository;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.oneequalone.dto.SchoolOneToOneSearch;
import com.querydsl.oneequalone.entity.SchoolEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
import static com.querydsl.oneequalone.entity.QSchoolEntity.schoolEntity;
@Repository
public class SchoolQueryRepository {
@Autowired
private JPAQueryFactory jpaQueryFactory;
public List<SchoolEntity> findOfOneEqualsOne() {
List<SchoolOneToOneSearch> schoolOneToOneSearchs = Arrays.asList(new SchoolOneToOneSearch[]{
SchoolOneToOneSearch.builder().no(1).address("Seoul").build(),
SchoolOneToOneSearch.builder().no(3).address("Busan").build(),
});
// 조건절
BooleanExpression booleanExpression = null;
if(schoolOneToOneSearchs.size() > 0) {
SchoolOneToOneSearch schoolOneToOneSearch = schoolOneToOneSearchs.get(0);
booleanExpression = schoolEntity.no
.eq(schoolOneToOneSearch.getNo())
.or(schoolEntity.address.eq(schoolOneToOneSearch.getAddress()));
}
for (int i=1; i<schoolOneToOneSearchs.size(); i++) {
SchoolOneToOneSearch schoolOneToOneSearch = schoolOneToOneSearchs.get(i);
booleanExpression = booleanExpression.and(
schoolEntity.no
.eq(schoolOneToOneSearch.getNo())
.or(schoolEntity.address.eq(schoolOneToOneSearch.getAddress()))
);
}
// 결과 반환
return jpaQueryFactory
.selectFrom(schoolEntity)
.where(booleanExpression)
.fetch();
}
}
booleanExpression에 명확한 초기 값을 세팅할 수 없기에 반복적인 쿼리를 작성하는 상황이 발생됩니다.
이를 효율적인 코드로 변경하기 위해 1=1을 활용해 보겠습니다.
where절에 1=1을 사용하는 경우
query를 살짝 수정하여 다음과 같이 만들어 볼 수 있습니다.
package com.querydsl.oneequalone.repository;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.oneequalone.dto.SchoolOneToOneSearch;
import com.querydsl.oneequalone.entity.SchoolEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
import static com.querydsl.oneequalone.entity.QSchoolEntity.schoolEntity;
@Repository
public class SchoolQueryRepository {
@Autowired
private JPAQueryFactory jpaQueryFactory;
public List<SchoolEntity> findOfOneEqualsOne() {
List<SchoolOneToOneSearch> schoolOneToOneSearches = Arrays.asList(new SchoolOneToOneSearch[]{
SchoolOneToOneSearch.builder().no(1).address("Seoul").build(),
SchoolOneToOneSearch.builder().no(3).address("Busan").build(),
});
// 조건절 동적 쿼리
BooleanExpression booleanExpression = Expressions.asString("1").eq("1");
for (SchoolOneToOneSearch schoolOneToOneSearch : schoolOneToOneSearches) {
booleanExpression = booleanExpression.and(
schoolEntity.no
.eq(schoolOneToOneSearch.getNo())
.or(schoolEntity.address.eq(schoolOneToOneSearch.getAddress()))
);
}
// 결과 반환
return jpaQueryFactory
.selectFrom(schoolEntity)
.where(booleanExpression)
.fetch();
}
}
1=1을 활용했더니 반복적인 query가 줄어들게 되고 코드가 클린 해진 것을 확인할 수 있습니다.
또한 해당 코드를 테스트해 보면 다음과 같이 코드가 정상적으로 실행되는 것도 확인할 수 있습니다.
select
schoolenti0_.no as no1_0_,
schoolenti0_.address as address2_0_,
schoolenti0_.name as name3_0_
from
school schoolenti0_
where
1=1
and (
schoolenti0_.no=1
or schoolenti0_.address='Seoul'
)
and (
schoolenti0_.no=3
or schoolenti0_.address='Busan'
)
추가로 위의 예시는 and문이 반복되기 때문에 1=1을 활용해 볼 수 있었습니다.
만약 and문이 반복되지 않고 or문이 반복된다면 1=1을 사용하는 대신에 1=0을 사용하여 동일한 쿼리를 짜볼 수 있습니다.
이상으로 QueryDSL where절에 1=1 사용하는 방법에 대해 간단하게 알아보는 시간이었습니다.
읽어주셔서 감사합니다.
'Spring > SpringBoot' 카테고리의 다른 글
[SpringBoot] MockMVC를 이용하여 API 테스트하기 (0) | 2023.04.09 |
---|---|
[SpringBoot] WebClient를 이용하여 외부 API 호출하기 (1) | 2023.03.15 |
[SpringBoot] 엑셀 파일 생성하여 다운로드하기 (0) | 2023.01.18 |
[SpringBoot] 이메일 발신하기 (0) | 2023.01.16 |
[SpringBoot] encodeURIComponent, decodeURIComponent 사용하기 (0) | 2022.12.29 |
댓글