프로젝트를 실행해보면 build/generated/annotationProcessor에 QClass가 생성된 것을 확인할 수 있다.
Query DSL을 사용하기 위해서는 EntityManager와 JPAQueryFactory를 Bean으로 등록해야 한다.
@Configuration
public class QueryDslConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
QueryDSL은 JPAQueryFactory 객체를 이용하여 사용하는데 EntityManager를 파라미터로 받아 사용한다.
EntityManager는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하여 Thread간에 공유가 되서는 안된다. 이를 해결하기 위해 @PersistenceContext를 통해 Thread-safe 상태를 유지한다.
RecuritRepository
public interface RecruitRepository extends JpaRepository<Recruit, Integer>, RecruitRepositoryCustom {
}
Spring Data JPA에서 기본적으로 제공하는 기능과 QueryDSL의 Custom 기능들을 하나의 인터페이스에서 사용할 수 있도록 했다.
RecuritRepositoryCustom
public interface RecruitRepositoryCustom {
List<Recruit> searchAll(RecruitDto.DetailListRequestDto requestDto);
}
RecuritRespositoryImpl
@RequiredArgsConstructor
public class RecruitRepositoryImpl implements RecruitRepositoryCustom {
private final JPAQueryFactory factory;
@Override
public List<Recruit> searchAll(RecruitDto.DetailListRequestDto requestDto) {
BooleanBuilder builder = new BooleanBuilder();
QRecruit recruit = QRecruit.recruit;
StringExpression start = Expressions.stringTemplate("FUNCTION('DATE_FORMAT', {0}, '%Y-%m')", recruit.start);
StringExpression end = Expressions.stringTemplate("FUNCTION('DATE_FORMAT', {0}, '%Y-%m')", recruit.end);
// 회사 필터
if(requestDto.getCompanyId() != 0) {
builder.and(recruit.company.id.eq(requestDto.getCompanyId()));
}
return factory
.selectFrom(recruit)
.join(recruit.company).fetchJoin()
.where(builder
.and(start.eq(requestDto.getDate()).or(end.eq(requestDto.getDate()))))
.fetch();
}
}