QueryDSL은 JPQL을 자바 코드로 작성할 수 있게끔 도와주는 오픈소스 라이브러리
JPQL을 자바 코드로 작성하게끔 지원해 주는 건 이것 말고도 여러가지 있긴 한데,
이거는 정말 코드가 직관적이다.
JPQL과 거의 유사해서 해석도 쉽다.
쿼리 dsl 쓰려면 우선,
설정을 해 줘야 하는데 이거는 스프링 부트 버전마다 다르다.
https://lordofkangs.tistory.com/461
그냥 검색하면 나온다.
def querydslSrcDir = 'src/main/generated'
clean {
delete file(querydslSrcDir)
}
tasks.withType(JavaCompile) {
options.generatedSourceOutputDirectory = file(querydslSrcDir)
}
여기 이 부분은 그렇게 설정해서 만든 Q(QueryDSL 자바 파일)파일을 어디다 위치시킬건지
여튼 이렇게 해 놓으면,
Gradle 창에서
Tasks -> other -> compileJava 하면 (외부 라이브러리 이니 other인듯)
명시해놓은 저 위치에 Q파일들이 생성됨.
도메인 별로 생김.
이제, 리포지토리에서 그걸 이용하면 됨.
public List<Order> findAll(OrderSearch orderSearch){
QOrder order = QOrder.order;
QMember member = QMember.member;
JPAQueryFactory query = new JPAQueryFactory(em);
return query.select(order)
.from(order)
.join(order.member, member)
.where(statusEq(orderSearch.getOrderStatus()), nameLike(orderSearch.getMemberName()))
.limit(1000)
.fetch();
}
private BooleanExpression statusEq(OrderStatus statusCond){
if(statusCond == null){
return null;
}
return QOrder.order.status.eq(statusCond);
}
private BooleanExpression nameLike(String memberName){
if(!StringUtils.hasText(memberName)){
return null;
}
return QMember.member.name.contains(memberName);
}
QOrder가 order에 대한 queryDSL용 정보라고 보면 됨.
queryDSL을 쓰면은 JPAQueryFactory, 즉 쿼리 공장이 있어야 함.
거기에 엔티티매니저를 넣어서 커넥션과 연동되게끔.
이제 그냥 jpql 짜듯이? 하면 됨.
select(가져올엔티티).from(근원).join(근원의뭐를조인할열쇠로삼을지, 조인할근원)
.where(조건,조건)
여기 이 조건 부분이 이제 핵심.
아래 보면 Boolean표현식을 반환토록 함. 저거 QueryDSL꺼임.
저렇게 만약 null이면 그냥 null을 반환하고, (그러면 where에서 null이면 그냥 무시함.)
뭔가 있으면 QOrder의 order의 status와 eq(인자), 즉 같은지 비교하는 쿼리를 만듦.
또 name도,
먼저 문자열 자체가 뭔가 있는지 확인해보고 텍스트가 없으면 null,
있으면 member근원의 name에 저 memberName을 contains 하고 있는 것,
쿼리로 따지면
m.name like '%:memberName%'
이런 식으로 짜 질듯.
저게 BooleanExpression에 담겨서 감.
그럼 where()에서 보고 null이면 거짓? 으로 하지 않고, 값이 있으면 where ~~ 하는 듯.
where()도 내부적으로 인자들이 모두 null이면 where조차 생성하지 않고, 또 and같은 것도 인자가 여러개가 참이면(null이 아니면) 알아서 붙여줄 거임. 그 정도는 구현하기 쉬움.
여튼 .limit(1000) 최대 1000개까지, 하고
fetch() 해서 끌어옴.
select
o1_0.order_id,
o1_0.delivery_id,
o1_0.member_id,
o1_0.order_date,
o1_0.status
from
orders o1_0
join
member m1_0
on m1_0.member_id=o1_0.member_id
where
o1_0.status=?
and m1_0.name like ? escape '!'
fetch
first ? rows only
2023-11-17T12:00:48.310+09:00 INFO 13116 --- [nio-8080-exec-2] p6spy : #1700190048310 | took 0ms | statement | connection 29| url jdbc:h2:tcp://localhost/./jpashop
select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.member_id=o1_0.member_id where o1_0.status='CANCEL' and m1_0.name like '%user%' escape '!' fetch first 1000 rows only;
일단은 order 쿼리 날라간 부분만 가져옴.
where 부분을 보셈. 둘다 비우지 않고 옵션을 준 경우임.
null이거나 비어있으면 그냥 안붙음. 둘다 옵션 없는 경우 where 자체가 없음. where()에서 다 처리함.
Q파일들, 그러니까 generated 된 것들은 build 타임에 생성되는거라 깃허브에 올릴 필요 없음. 빼주셈. 깃허브에 올릴 때
limit 꼭 붙일 필요는 없다고 chat GPT가 그럼. 여튼 제대로 배우기 시작하면 알게 될거임.
그리고, 우리가 new 오퍼레이션 쓰면서 Dto로 직접받는 거 할 때, 패키지 경로까지 다 명시해 줬었어야 했는데,
QueryDSL을 쓰면 패키지명도 안써도 되고 생성자도 사용가능하고 setter도 사용가능하다고 한다.
자세한 건 나중에..
그리고, 꼭 동적 쿼리가 아니라 정적 쿼리인 경우에도 QueryDSL을 사용하면 이점이 있다.
직관적이고
컴파일 시점에 문법 오류 발견하고
코드 자동완성
코드 재사용
Dto 정말 간편하게 지원 등
나는 직관적인건 JPQL이 더 직관적이고 문법 오류도 사실 인텔리제이가 jpql? sql도 그런가? 여튼 문자열인데도 문법오류를 잡아주는 듯 하다.
자동완성이 정말 편리할 듯.
근데 일단 SQL, 그 후 JPQL에 익숙해 져야 함.
또, Dto는 그냥 QueryDSL로 받는 게 좋을 듯.
JPQL이 할 수 있는 건 거의 다 지원해 준다고 한다.
또 재사용성.
확실히 인자로 받아서 그냥 넣어주면 될 것 같다.
즉, 조립이 쉽다.
'스프링데이터 + JPA > QueryDSL' 카테고리의 다른 글
5. H2 DB 설치 및 설정 (0) | 2023.11.27 |
---|---|
4. 연관 라이브러리 (0) | 2023.11.27 |
3. QueryDSL 설정 (0) | 2023.11.27 |
2. 프로젝트 생성 (0) | 2023.11.27 |
1. 소개 (0) | 2023.11.27 |