⚡ 개요
queryDsl을 사용하면서 데이터를 조회하거나, 조건을 추가할 때 case when 구문을 사용해야 하는 경우가 발생한다.
내부적으로는 이력을 조회하거나, 카운트를 조회 한다거나 조건을 추가하려고 stream의 중간 연산자를 쓰는 것보다 쿼리를 한 번에 날려서 조회하는 게 속도적으로 좀 더 좋다고 판단해서 사용하고 있다.
물론 일반적인 비지니스 로직에서 처리를 할 때는 최대한 사용하지 않는 게 좋다고 생각하기는 하지만 분명 어쩔 수 없는 경우도 있을 것이다. 좋지 않다고 해서 사용을 안 하는 것이 아니라 상황에 맞게 판단해서 사용하는 게 좋다고 생각을 한다.
⚡ case when 사용 방식 정리
일단 가장 기본적으로 queryDsl 에서 caseBuilder를 사용해서 case when 구문을 사용하는 방법에 대해서 정리하려고 한다.
@Service
public class TestServiceImpl implements TestService {
private final JPAQueryFactory queryFactory;
@Transactional(readOnly = true)
public TestDto getTestDto() {
return queryFactory
.select(
Projections.fields(
TestDto.class,
Qtest.test.id.as("id"),
Qtest.test.name.as("name"),
new CaseBuilder()
.when(Qtest.test.type.eq("1")).then("테스트1")
.otherwise("test2")
.as("type")
)
)
.from(Qtest.test)
.fetch();
}
}
기본적인 case when문에 대해서 샘플 소스를 작성해봤다.
추가적으로 사용 가능한 옵션에 대한 설명을 정리 하도록 하겠다.
- when : 쿼리에서도 많이 봤을것이다. 조건문이다.
- then : when 절이 true인 경우에 반환되는 값이다.
- otherwise : when 절이 false인 경우에 반환되는 값이다.
- as : 반환할 필드명을 명시적으로 선언해줘야 한다. 기본적인 경우는 Entity에 매핑된 값이 리턴되지만 case 문의 경우는 매핑된 값이 없기 때문에 에러가 발생한다.
위의 기본적인 내용만 사용해도 충분히 사용하는데 문제는 없지만 case when 안에 또 다른 case when이 존재 해야 하는 경우가 있다. 이 부분에 대해서 위의 내용과 크게 다른 점은 없지만 테스트 코드를 작성해봤다.
@Service
public class TestServiceImpl implements TestService {
private final JPAQueryFactory queryFactory;
@Transactional(readOnly = true)
public TestDto getTestDto() {
return queryFactory
.select(
Projections.fields(
TestDto.class,
Qtest.test.id.as("id"),
Qtest.test.name.as("name"),
new CaseBuilder()
.when(Qtest.test.type.eq("1"))
.then(new CaseBuilder()
.when(Qtest.test.type2.eq("2"))
.then("test")
.otherwise("test2")
)
.otherwise("test2")
.as("type")
)
)
.from(Qtest.test)
.fetch();
}
}
소스를 보면 then 또는 otherwise 내부에 CaseBuilder()를 한번 더 사용해서 처리를 하면 된다.
레거시 시스템의 경우에는 옵셥을 여러 개를 보는 경우가 많이 존재하고 해당 옵션에 따라 다른 옵션도 정해지는 경우가 많이 존재한다. 이런 경우에 쿼리를 마이그레이션 하는 과정에서 사용이 가능하다고 생각한다.
⚡ 추가적인 정보
위의 내용과 동일하지만 추가적으로 다르게 사용하는 방법에 대해서 샘플 코드를 하나 정리 하려고 한다.
@Service
public class TestServiceImpl implements TestService {
private final JPAQueryFactory queryFactory;
@Transactional(readOnly = true)
public TestDto getTestDto() {
var testCnt = new CaseBuilder()
.when(Qtest.test.type.eq("1"))
.then(1)
.otherwise(0)
.sum();
return queryFactory
.select(testCnt)
.from(Qtest.test)
.fetch();
}
}
어떻게 사용하냐에 따라 다르겠지만 가령 sum 값을 queryFactory에서 구해야 하는 경우가 있다면 충분히 활용 가능하다고 생각한다.
caseBuilder에 대한 사용 방법에 대해서 정리를 해봤다. 최대한 사용하지 않는 방향으로 설계를 하고 구조를 잡아서 처리하면 좋겠지만 사용을 해야 하는 상황이 온다면 상황에 맞게 최선의 선택을 해서 사용을 하면 좋을 거 같다.
'Spring' 카테고리의 다른 글
[JPA] save() 와 saveAndFlush() 차이점 정리 (0) | 2023.10.29 |
---|---|
[JPA] repository를 통해서 일부 컬럼만 조회하는 방법 정리 (0) | 2023.10.09 |
[Spring] Spring boot 3.0 + JPA 관련 gradle 설정 정리 (0) | 2023.09.25 |
[Spring] Spring Event 기능 구현하기 ApplicationEventPublisher 이용하기 (0) | 2023.08.05 |
[JPA] Spring Boot 에서 QueryDsl 사용 방법 정리 (0) | 2023.06.24 |