지우쓰 개발일기
[JPA] QueryDSL 본문
본 포스팅은 자바 ORM 표준 JPA 프로그래밍 (김영한 저)을 읽고 정리한 내용입니다.
자바 ORM 표준 JPA 프로그래밍
에이콘 오픈 소스 프로그래밍 시리즈. 이 책은 JPA 기초 이론과 핵심 원리, 그리고 실무에 필요한 성능 최적화 방법까지 JPA에 대한 모든 것을 다룬다.
www.aladin.co.kr
QueryDSL
JPQL을 코드로 쉽고 간결하게 작성할 수 있는 프로젝트
시작
public void queryDSL() {
EntityManager em = emf.createEntityManager();
JPAQuery query = new JPAQuery(em); // 생성자 파라미터로 EntityManager
QMember qMember = new QMember("m"); // 생성되는 JPQL 별칭 지정
List<Member> members =
query.from(qMember)
.where(qMember.name.eq("회원1"))
.orderBy(qMember.name.desc())
.list(qMember);
}
기본 Q(쿼리 타입) 생성
QMember qMember = new QMember("m"); // 직접 지정
QMember qMember = QMember.member; // 기본 인스턴스 사용
-
쿼리 타입은 기본 인스턴스를 보관하고 있음
-
같은 엔티티를 조인하거나 같은 엔티티를 서브쿼리에 사용 시 별칭을 직접 지정해야 함
-
기본 인스턴스 사용 시 import하여 간결하게 쓸 수 있음
검색 조건 쿼리
-
where절에 between, contains, startsWith 등 적절한 메소드 사용
- 중복 조건(and, or) 가능
결과 조회
메소드 | 결과가 한 건일 때 | 결과가 한 건 이상일 때 | 결과가 없을 때 |
uniqueResult() | O | NonUniqueResultException | null |
singleResult() | O | 첫 데이터 | null |
list() | O | O | 빈 컬렉션 |
listResults() | O | O | 빈 컬렉션 |
Paging & 정렬
-
offset(), limit()
query.from(item)
.orderBy(item.price.desc(), item.stockQuantity.asc())
.offset(10).limit(20)
.list(item);
-
QueryModifiers
QueryModifiers queryModifiers = new QueryModifiers(20L, 10L); // limit, offset
query.from(item)
.restrict(queryModifiers)
.list(item);
-
listResults()
SearchResults<Item> result =
query.from(item)
.where(item.price.gt(10000))
.offset(10).limit(20)
.listResults(item);
long total = result.getTotal();
long limit = result.getLimit();
long offset = result.getOffset();
List<Item> results = result.getResults();
그룹
query.from(item)
.groupBy(item.price)
.having(item.price.gt(1000))
.list(item);
조인
-
join(조인 대상, 별칭으로 사용할 쿼리 타입)
-
innerJoin(join), leftJoin, rightJoin, fullJoin
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);
-
fetch join
query.from(order)
.innerJoin(order.member, member).fetch()
.list(order);
-
theta join
query.from(order, member)
.where(order.member.eq(member))
.list(order);
서브 쿼리
-
서브 쿼리 결과가 한 건
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);
-
서브 쿼리 결과가 여러 건
query.from(item)
.where(item.in(
new JPASubQuery().from(itemSub)
.where(item.name.eq(itemSub.name))
.list(itemSub)
))
.list(item);
프로젝션 결과
-
프로젝션 대상이 하나
QItem item = QItem item;
List<String> results = query.from(item).list(item.name);
-
여러 컬럼 반환과 튜플
List<Tuple> results = query.from(item).list(item.name, item.price);
for (Tuple tuple : results) {
String name = tuple.get(item.name);
Integer price = tuple.get(item.price);
}
-
빈 생성
// 1. Setter
List<ItemDTO> result = query.from(item).list(
Projections.bean(ItemDTO.class, item.name.as("username"), item.price)
);
// 2. Field
List<ItemDTO> result = query.from(item).list(
Projections.bean(ItemDTO.class, item.name.as("username"), item.price)
);
// 3. Constructor
List<ItemDTO> result = query.from(item).list(
Projections.constructor(ItemDTO.class, item.name, item.price)
);
수정, 삭제 배치 쿼리
-
Persistence Context를 무시하고 DB에 직접 쿼리함
-
수정
QItem item = QItem.item;
JPAUpdateClause updateClause = new JPAUpdateClause(em, item);
long count = updateClause.where(item.name.eq("keyword"))
.set(item.price, item.price.add(100))
.execute();
-
삭제
QItem item = QItem.item;
JPADeleteClause deleteClause = new JPADeleteClause(em, item);
long count = deleteClause.where(item.name.eq("keyword"))
.execute();
동적 쿼리
-
com.mysema.query.BooleanBuilder
SearchParam param = new SearchParam();
param.setName("keyword");
param.setPrice(1000);
QItem item = QItem.item;
BooleanBuilder builder = new BooleanBuilder;
if (StringUtils.hasText(param.getName()) {
builder.and(item.name.contains(param.getName());
}
if (param.getPrice() != null) {
builder.and(item.price.gt(param.getPrice()));
}
List<Item> results = query.from(item)
.where(builder)
.list(item);
'Spring Boot > JPA' 카테고리의 다른 글
[JPA] Spring Data JPA, JpaRepository (0) | 2020.09.25 |
---|---|
[JPA] JPQL (5) (0) | 2020.09.24 |
[JPA] JPQL (4) (0) | 2020.09.21 |
[JPA] JPQL (3) (0) | 2020.09.21 |
[JPA] JPQL (2) (0) | 2020.09.20 |
Comments