QueryDSL은 쿼리를 문자가 아닌 코드로 작성하고, 쉽고 간결하며 그 모양도 쿼리와 비슷하게 개발할 수 있다
10.4.2 시작
public void queryDSL(){
EntityManager em = emf.createEntityManager();
JPAQuery query = new JPAQuery(em);
QMember qMember = new QMember("m"); //생성되는 JPQL의 별칭이 m
List<Member> members =
query.from(qMember)
.where(qMMeber.name.eq("회원1")
.orederBy(qMember.name.desc())
.list(qMember);
}
- 엔티티 매니저를 생성자에 넘겨준다
- 쿼리 타입(Q)를 생성하는데 생성자에는 별칭을 주면 된다
- 이 별칭을 JPQL에서 별칭으로 사용한다
10.4.3 검색 조건 쿼리
JPAQuery query = new JPAQuery(em);
QItem item = QItem.item;
List<Item> list = query.from(item)
.where(item.name.eq("좋은상품").and(item.price.gt(20000))
.list(item); //조회할 프로젝션 지정
- QueryDSL의 where 절에는 and나 or을 사용할 수 있다
- 코드로 작성되어 있으므로 IDE가 제공하는 코드 자동 완성 기능의 도움을 받으면 필요한 메서드를 손쉽게 찾을 수 있다
10.4.4 결과 조회
대표적인 결과 조회 메서드
- uniqueResult()
- 조회 결과가 한 건일 때 사용한다
- 조회 결과가 없으면 null, 결과가 하나 이상이면 예외가 발생한다
- singleResult()
- uniqueResult()와 같지만 결과가 하나 이상이면 처음 데이터를 반환한다
- list()
- 결과가 하나 이상일 때 사용한다.
- 결과가 없으면 빈 컬렉션을 반환한다
10.4.5 페이징과 정렬
QItem item = QItem.item;
query.from(item)
.where(item.price.gt(20000))
.orderBy(item.price.desc(), item.stockQueantity.asc())
.offset(10).limit(20)
.list(item);
- 정렬을 orderBy를 사용하고, 쿼리 타입(Q)가 제공하는 asc(), desc()을 사용한다
- 페이징은 offset과 limit을 적절히 조합해서 사용하면 된다
SearchResult<Item> result =
query.from(item)
.where(item.price.gt(20000))
.orderBy(item.price.desc(), item.stockQueantity.asc())
.offset(10).limit(20)
.list(item);
long total = result.getTotal(); //검색된 전체 데이터 수
long limit = result.getLimit();
long offset = result.getOffset();
List<Item> results = result.getResults(); //조회된 데이터
- listResult()를 사용하면 전체 데이터 조회를 위한 count 쿼리를 한 번 더 실행한다
- 그리고 SearchResults를 반환하는데 이 객체에서 전체 데이터 수를 조회할 수 있다
10.4.6 그룹
query.from(item)
.groupBy(item.price)
.having(item.price.gt(1000))
.list(item);
- 그룹은 groupBy를 사용하고 그룹화된 결과를 제한하려면 having을 사용하면 된다
10.4.7 조인
- 조인은 iinerJoin(join), leftJoin, rightJoin, fullJoin을 사용할 수 있고 추가로 JPQL의 on과 성능 최적화를 위한 fetch 조인도 사용할 수 있다
QOrder order = QOrder.order;
QMember member = QMember.member;
QOrderItem orderItem = QOrderItem.orderItem;
query.from(Order)
.join(order.member, member)
.leftJoin(order.orderItems, orderItem)
.list(order);
- 가장 기본적인 조인 방법
query.from(order)
.leftJoin(order.orderItems, orderItem)
.on(orderItem.count.gt(2))
.list(order);
- 조인에 on을 사용한다
query.from(order)
.innerJoin(order.member, member).fetch()
.leftJoin(order.orderItems, orderItem).fetch()
.list(order);
- 패치 조인을 사용하는 방법이다
QOrder order = QOrder.order;
QMember member = QMember.member;
query.from(order, member)
.where(order.member.eq(member))
.list(order);
- from 절에 여러 조인을 사용하는 세타 조인 방법
10.4.8 서브 쿼리
- 서브 쿼리는 com.mysema.query.jpa.JPASubQuery를 생성해서 사용한다
QItem item = QItem.item;
QItem itemSub = new QItem("itemSub");
query.from(item)
.where(item.price.eq(
new JPASubQuery().from(itemSub).unique(itemSub.price.max())
))
.list(item);
- 서브 쿼리의 결과가 하나면 unique()를 사용한다
QItem item = QItem.item;
QItem itemSub = new QItem("itemSub");
query.from(itme)
.where(item.in)(
new JPASubQuery().from(itemSub)
.where(item.name.eq(itemSub.name))
.list(itemSub)
))
.list(item);
- 서브 쿼리의 결과가 여러 건이면 list()를 사용한다
10.4.9 프로젝션과 결과 반환
- select 절에 조회 대상을 지정하는 것을 프로젝션이라고 한다
QItem item = QItem.item;
List<String> result = query.from(item).list(item.name);
for(String name:result){
System.out.println("name = " + name);
}
- 프로젝션 대상이 하나일 때
QItem item = QItem.item;
List<Tuple> result = query.from(item).list(item.name,item.price);
for(Tuple tuple:result){
System.out.println("name = " + tuple.get(item.name));
System.out.println("price = " + tuple.get(item.price));
}
- 프로젝션 대상으로 여러 필드를 선택하면 com.mysema.query.Tuple 이라는 내부 타입을 사용한다
빈 생성
- 쿼리 결과를 엔티티가 아닌 특정 객체로 받고 싶으면 빈 생성(Bean population) 기능을 사용한다
- QueryDSL은 객체를 생성하는 다양한 방법을 제공한다
- 프로퍼티 접근
- 필드 직접 접근
- 생성자 사용
QItem item = QItem.item;
List<ItemDTO> result = query.from(item).list(
Projections.bean(ItemDTO.class, item.name.as("username"), item.price));
- 프로퍼티 접근(Setter)
QItem item = QItem.item;
List<ItemDTO> result = query.from(item).list(
Projections.fields(ItemDTO.class, item.name.as("username"), item.price));
- 필드 직접 접근
QItem item = QItem.item;
List<ItemDTO> result = query.from(item).list(
Projections.bean(ItemDTO.class, item.name.as("username"), item.price));
- 생성자 사용
'JPA 프로그래밍' 카테고리의 다른 글
Ch12. 스프링 데이터 JPA (0) | 2025.01.22 |
---|---|
Ch10. 객체 지향 쿼리 언어 (10.5 네이티브 SQL, 10.6 객체지향 쿼리 심화) (0) | 2025.01.21 |
Ch10. 객체지향 쿼리 언어 (10.3 Criteria) (1) | 2025.01.20 |
Ch10. 객체지향 쿼리 언어 (10.1 객체지향 쿼리 소개, 10.2 JPQL) (0) | 2025.01.20 |
Ch.9 값 타입 (1) | 2025.01.16 |