QueryDSL
QueryDsl : 정적 타입을 이용해서 SQL과 같은 쿼리를 생성할 수 있도록 해 주는 오픈소스 프레임워크
build gradle 에 queryDsl 관련 종속성을 설치 한후 Q 클래스를 만들수 있다.
Q클래스 : 엔티티 클래스의 메타 정보를 담고 있는 클래스로 Querydsl 은 이를 이용하여 타입 안전성을 보장하여 쿼리를 작성할수 있게 된다 .
Q클래스를 사용하면 컴파일 시점에 오류를 확인할수 있고 IDE 의 자동완성 기능을 이용해서 간편하게 작성가능하다 .
Qclass 엔티티 속성의 타입을 정확하게 표현하므로 ,타입에 맞지 않은 연산이나 비교를 시도하면 컴파일러 가 오류를 감지할수 있다.
관리자 검색에 대해 queryDsl로 구현해보자
public interface AdminRepositoryCustom {
Page<ReadAdminResponse> searchAdmin(AdminSearchCondition condition, Pageable pageable);
}
public interface AdminRepository extends JpaRepository<Admin, Long>, AdminRepositoryCustom {
AdminRepository 에는 AdminRepositoryCustom 을 JPA 옆에 상속해주면 된다.
public class AdminRepositoryImpl implements AdminRepositoryCustom {
private final JPAQueryFactory queryFactory;
public AdminRepositoryImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}
@Override
public Page<ReadAdminResponse> searchAdmin(AdminSearchCondition condition, Pageable pageable) {
List<ReadAdminResponse> content = queryFactory
.select(new QReadAdminResponse(
admin.adminSeq,
admin.adminId,
admin.role,
admin.nickname,
admin.name,
admin.depart
))
.from(admin)
.where(
adminIdEq(condition.getAdminId()),
nicknameEq(condition.getNickname()),
nameEq(condition.getName()),
departEq(condition.getDepart())
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
JPAQuery<Admin> countQuery = queryFactory
.select(admin)
.from(admin)
.where(
adminIdEq(condition.getAdminId()),
nicknameEq(condition.getNickname()),
nicknameEq(condition.getName()),
departEq(condition.getDepart())
);
return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchCount);
}
private BooleanExpression adminIdEq(String adminId) {
return hasText(adminId) ? admin.adminId.eq(adminId) : null;
}
private BooleanExpression nameEq(String name) {
return hasText(name) ? admin.name.eq(name) : null;
}
private BooleanExpression departEq(String depart) {
return hasText(depart) ? admin.depart.eq(depart) : null;
}
private BooleanExpression nicknameEq(String nickname) {
return hasText(nickname) ? admin.nickname.eq(nickname) : null;
}
}
AdminRepositoryImpl 에 대해 자세히 살펴보자면
queryFactory
.select(new QReadAdminResponse(
admin.adminSeq,
admin.adminId,
admin.role,
admin.nickname,
admin.name,
admin.depart
))
JPQL 에서는 프로젝션 관련해서 길게 작성을 했지만 QueryDsl에서는 DTO 부분에 @QueryProjection 을 사용하여서 예쁘게 빼올수 있다.
JPAQuery<Admin> countQuery = queryFactory
.select(admin)
.from(admin)
.where(
adminIdEq(condition.getAdminId()),
nicknameEq(condition.getNickname()),
nicknameEq(condition.getName()),
departEq(condition.getDepart())
);
private BooleanExpression adminIdEq(String adminId) {
return hasText(adminId) ? admin.adminId.eq(adminId) : null;
}
where 절의 경우에는 다음과 같은 private 메서드를 이용해서 조건 처리를 해준다.
JPQL 의 경우에는 repository 에서 해당 필터링에 대해서 메서드를 하나씩 다 만들어줘야 하지만
queryDsl의 경우에는 AdminSearchCondition DTO 부분에 필터링 내용을 추가하고
AdminRepositoryImpl 에 관련 내용을 추가해주면 된다.