본문 바로가기
Spring/SpringBoot

[SpringBoot] QueryDSL where절에 1=1 사용하기

by J4J 2023. 1. 25.
300x250
반응형

안녕하세요. 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();
    }
}

 

 

728x90

 

 

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 사용하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글