
QueryDSL은 JPA에서 복잡한 쿼리나 동적쿼리를 작성할 때 도움을 주는 라이브러리입니다.
물론 JPQL을 사용하여 쿼리를 작성할수도 있지만 JPQL의 가장 큰 단점은 문자열을 통해 쿼리를 작성한다는 것입니다.
문자열을 통해 쿼리를 작성하게 되면 컴파일 단계에서 오류를 발견하기 어렵습니다.
또한 동적쿼리를 작성할 때도 if문으로 감싸져 있기 때문에 가독성이 좋지 않습니다.
그렇기 때문에 자바 코드를 사용하여 쉽고 간결하게 쿼리를 작성할 수 있는 QueryDSL을 사용했습니다.
QueryDSL 설정은 maven을 사용한다면 의존성만 추가해주면 되지만,
gradle로 설정하는 방법은 공식문서에 없어서 따로 설정해줘야 합니다.
일단 QueryDSL의 버전에 따라 설정 방법이 다릅니다.
4버전까지는 복잡하게 설정을 해야했지만
5버전부터는
// QueryDSL
implementation "com.querydsl:querydsl-jpa:5.0.0"
implementation "com.querydsl:querydsl-core:5.0.0"
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jpa'
annotationProcessor "javax.persistence:javax.persistence-api"
annotationProcessor "javax.annotation:javax.annotation-api"
//dependencies 밖에 추가
sourceSets {
main {
java {
srcDir("$projectDir/build/generated")
}
}
}
이렇게 추가만 하면 됩니다.
빌드를 하게 되면 build/generated 폴더 안에 entity가 작성되어 있는 폴더 안에 Q로 시작하는 entity가 생깁니다.
주의할 점은 clean하기 전에 빌드를 다시 한다면 이미 만들어진 entity라고 오류가 생깁니다.
이때는 clean을 먼저 하고 빌드를 하면 해결됩니다.
먼저 import static com.conseller.conseller.entity.QAuction.*auction*; 처럼 Qentity의 객체를 가져옵니다.
private final JPAQueryFactory factory; factory 객체를 의존성 주입해줍니다.
기본적으로 factory 객체에 메서드 체이닝으로 쿼리문을 작성합니다.
selectFrom() : select와 from이 같다면 사용한다. Qentity를 넣어주면 됩니다.
select() : 찾고싶은 Q엔티티를 넣으면 엔티티가 반환되고, 원하는 컬럼만 찾고 싶다면 컬럼을 지정해 줄 수 있습니다.
QUser user = QUser.user;
List<Tuple> results = new JPAQuery<>(entityManager)
.select(user.userIdx, user.userName)
.from(user)
.where(user.username.eq("대화"))
.fetch();
컬럼을 지정해준다면 Tuple 객체 형태로 반환이 되고 get을 통해서 값을 확인할 수 있습니다.
for (Tuple row : results) {
Long userIdx = row.get(user.userIdx);
String userName = row.get(user.userName);
// ... 이후의 처리
}
from() : 검색하고 싶은 Q엔티티를 넣습니다.
where() : 검색하고 싶은 조건을 BooleanExpression으로 추가합니다.
자주 사용하는 Boolean Expression 연산자
이 조건을 직접 where안에 넣어줄 수 있지만
함수의 형태로 만들어 값이 없다면 null을 반환하고, 값이 있다면 원하는 BooleanExpression을 반환해 동적 쿼리를 작성할 수 있습니다.
BooleanExpression이 null이라면 조건을 무시합니다.
private BooleanExpression eqSearch(String searchQuery) {
if(!StringUtils.hasText(searchQuery)){
return null;
}
return auction.gifticon.gifticonName.containsIgnoreCase(searchQuery);
}
위와 같이 검색어가 없다면 null 있으면 검색어를 조건에 넣습니다.
orderBy() : 정렬 조건, OrderSpecifier 객체를 만들어 원하는 상태에 따라 정렬할 수 있도록 했습니다.
private OrderSpecifier orderSpecifier(Integer status) {
if(status == 0) {
return new OrderSpecifier(Order.DESC, auction.auctionStartDate);
} else if (status == 1) {
return new OrderSpecifier(Order.ASC, auction.gifticon.gifticonEndDate);
} else if(status == 2) {
return new OrderSpecifier(Order.ASC, auction.auctionHighestBid);
} else {
return new OrderSpecifier(Order.ASC, auction.upperPrice);
}
}
groupBy() : 그룹화
having() : 그룹화 조건
offset() : pageable을 사용하기 위한 메서드, 시작하는 페이지를 정해줍니다.
limit() : 위에서부터 n개의 데이터를 가져옵니다.
이러한 메서드를 사용하여 쿼리문을 작성할 수 있습니다.
서브쿼리를 만들 때에는 2가지 방법이 있는데
JPAExpressions로 만드는 방법과 JPASubQuery로 만드는 방법입니다.
JPAExpressions는 주로 간결하게 쿼리의 특정 부분에 서브쿼리를 삽입할 때 사용합니다.
JPASubQuery는 객체를 통해 서브쿼리를 생성하고, 좀 더 복잡한 쿼리문을 작성할 때 사용합니다.
확실히 초기 설정만 잘 한다면 편리하고 좋은 라이브러리인 것 같다.