자바 ORM 표준 JPA 프로그래밍

[자바 ORM 표준 JPA 프로그래밍] 10.4 - QueryDSL

2023. 7. 22. 01:58
목차
  1. 2. 시작
  2. 3. 검색 조건 쿼리
  3. 4. 결과 조회
  4. 5. 페이징과 정렬
  5. 6. 그룹
  6. 7. 조인
  7. 8. 서브쿼리
  8. 9. 프로젝션 결과 반환
  9.  
  10. 10. 수정, 삭제 배치 쿼리
  11. 11. 동적 쿼리
  12. 12. 메소드 위임
 

자바 ORM 표준 JPA 프로그래밍 | 김영한 - 교보문고

자바 ORM 표준 JPA 프로그래밍 | 자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA

product.kyobobook.co.kr

 

QueryDSL은 쿼리를 문자가 아닌 코드로 작성하여 쉽고 간결하며 그 모양도 쿼리와 비슷하게 개발할 수 있는 프로젝트이다. 코드로 JPQL을 작성하므로 문법 오류를 컴파일 단계에서 잡을 수 있고 IDE 자동완성 기능의 도움을 받을 수 있다

 

2. 시작

  • 라이브러리 추가와 쿼리용 클래스 생성
  • com.mysema.query.jpa.impl.JPAQuery 객체를 생성해야 하며, 사용할 쿼리 타입(Q)을 생성할 때 생성자에는 별칭을 준다.

 

기본 Q 생성

  • 쿼리 타입(Q)은 기본 인스턴스를 보관하고 있다.
  • 같은 엔티티를 조인하거나 같은 엔티티를 서브쿼리에 사용하면 같은 별칭이 사용되므로 이때는 별칭을 직접 지정해서 사용해야 한다.
  • QMember qMember = new QMember("m"); // 별칭 직접 지정 QMember qMember = QMember.member; // 기본 인스턴스 사용
public void queryDSL() {
    EntityManager em = emf.createEntityManager();

    JPAQuery query = new JPAQuery(em);
    QMember qMember = new QMember("m");
    List<Member> members =
        query.from(qMember)
            .where(qMember.name.eq("회원1"))
            .orderBy(qMember.name.desc())
            .list(qMember);
}

 

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);
// 생성된 JPQL
select item
from Item item
where itme,name =?1 and item.price>?2
  • QueryDsl의 where 절에는 and 나 or을 사용할 수 있고, 여러 검색 조건을 사용해도 된다,
  • 쿼리 타입의 필드는 필요한 대부분의 메소드를 명시적으로 제공한다.
    • ex ) .between() .contains() .startsWith()

 

4. 결과 조회

쿼리 작성이 끝나고 결과 조회 메소드를 호출하면 실제 데이터베이스를 조회한다.

  • uniqueResult() : 조회 결과가 한 건일 때 사용한다. 조회 결과가 없으면 null / 하나 이상이면 예외가 발생
  • singleResult() : 조회 결과가 하나 이상이면 처음 데이터를 반환한다.
  • list() : 결과가 여러 개일 때 모두 반환하며, 결과가 없으면 빈 컬렉션을 반환한다.

 

5. 페이징과 정렬

  • 정렬은 orderby를 사용하는데 쿼리 타입이 제공하는 asc() desc() 를 사용한다.
  • 페이징은 offset과 limit를 적절히 조합해서 사용한다.
query.from(item)
    .where(item.price.gt(20000))
    .orderBy(item.price.desc(), item.stockQuantity.asc())
    .offset(10).limit(20)
    .list(item);
  • 실제 페이징 처리를 하려면 검색된 전체 데이터 수를 알아야 해서 list 대신 listReults()를 사용한다.

 

6. 그룹

  • groupBy와 having 사용
query.from(item)
    .groupBy(ite.price)
    .having(item.price.gt(1000))
    .list(item);

 

7. 조인

  • 내부조인, 외부조인, 페치조인 사용 가능
  • join(조인 대상, 별칭으로 사용할 쿼리 타입)
// 기본 조인
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);

// 조인 on 사용
query.from(order)
    .leftJoin(order.orderItems, orderItem)
    .on(orderItem.cont.gt(2))
    .list(order);

// 페치 조인
query.from(order)
    .innerJoin(order.member, member).fetch()
    .leftJoin(order.orderItems, orderItem).fetch()
    .list(order);

// 세타 조인
query.from(order, member)
    .where(order.member.eq(member))
    .list(order);

 

8. 서브쿼리

  • com.mysema.query.jpa.JPASubQuery 를 생성하여 서브 쿼리를 사용
  • 서브 쿼리의 결과가 하나면 unique() , 여러 개면 list() 를 사용
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);

 

9. 프로젝션 결과 반환

  • select절에 조회 대상을 지정하는 것을 프로젝션이라고 한다.

 

프로젝션 대상이 하나

  • 해당 타입으로 반환
QItem item = QItem.item;
List<String> result = query.from(item).list(item.name);

 

여러 컬럼 반환과 튜플

  • QueryDSL은 Map과 비슷한 Tuple 자료형을 지원한다.
QItem item = QItem.item;
List<Tuple> result = query.from(item).list(item.name, list.price);

// 같은 의미
List<Tuple> result = query.from(item).list(new QTuple(item.name, list.price));

// tuple.get()으로 조회

 

빈 생성

  • 쿼리 결과를 특정 객체로 받고 싶으면 QueryDSL의 빈 생성 기능을 사용할 수 있다.
public class ItemDTO {

    private String username;
    private int price;

    // 생성자
    // getter, setter
}
  • 프로퍼티 접근 (setter)
    • Projections.bean() 메소드는 setter를 사용해서 값을 채워 준다.
    • QItem item = QItem.item; List<ItemDTO> result = query.from(item).list( Projections.bean(ItemDTO.class, item.name.as("username"), item.price));
  • 필드 직접 접근
    • Projections.fields() 는 필드에 직접 접근
    • QItem item = QItem.item; List<ItemDTO> result = query.from(item).list( Projections.fields(ItemDTO.class, item.name.as("username"), item.price));
  • 생성자 사용
    • Projections.constructor() 는 생성자를 사용
    • QItem item = QItem.item; List<ItemDTO> result = query.from(item).list( Projections.constructor(ItemDTO.class, item.name.as("username"), item.price));

 

 

10. 수정, 삭제 배치 쿼리

  • QueryDSL도 JPQL 배치 쿼리와 같이 영속성 컨텍스트를 무시하고 데이터베이스를 직접 쿼리한다.
  • 수정 배치 쿼리 : com.mysema.query.jpa.impl.JPAUpdateClause
  • 삭제 배치 쿼리 : com.mysema.query.jpa.impl.JPADeleteClause
QItem item = QItem.item;

// 수정 배치 쿼리
JPAUpdateClause updateClause = new JPAUpdateClause(em, item);
long count = updateClause.where(item.name.eq("시골 개발자의 JPA 책"))
    .set(item.price, item.price.add(100))
    .execute();

// 삭제 배치 쿼리
JPADeleteClause deleteClause = new JPADeleteClause(em, item);
long count = DeleteClause.where(item.name.eq("시골 개발자의 JPA 책"))
    .execute();

 

 

11. 동적 쿼리

  • com.mysema.query.BooleanBuilder 를 사용하여 특정 조건에 따른 동적 쿼리를 편리하게 생성할 수 있다.
SearchParam param = new SearchParam();
param.setName("시골 개발자");
param.setPrice(10000);

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> result = query.from(item)
    .where(builder)
    .list(item);

 

 

12. 메소드 위임

  • 메소드 위임 기능을 사용하면 쿼리 타입에 검색 조건을 직접 정의할 수 있다.
//검색 조건 정의
public class ItemExpression {

        @QueryDelegate(Item.class)
        public static BooleanExpression isExpensive(QItem item, Integer price) {
                return item.price.gt(price);
        }
}

//쿼리 타입에 생성된 결과
public class QItem extends EntityPathBase<Item> {
        ...
        public BooleanExpression isExpensive(Integer price) {
        return ItemExpression.isExpensive(this, price);
    }
}

 

저작자표시 (새창열림)

'자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글

[자바 ORM 표준 JPA 프로그래밍] 13장 - 웹 애플리케이션과 영속성 관리  (0) 2023.07.26
[자바 ORM 표준 JPA 프로그래밍] 12장 - 스프링 데이터 JPA  (0) 2023.07.26
[자바 ORM 표준 JPA 프로그래밍] 10.2 - JPQL  (0) 2023.07.22
[자바 ORM 표준 JPA 프로그래밍] 9장 - 값 타입  (0) 2023.07.22
[자바 ORM 표준 JPA 프로그래밍] 8장 - 프록시와 연관관계 관리  (0) 2023.06.13
  1. 2. 시작
  2. 3. 검색 조건 쿼리
  3. 4. 결과 조회
  4. 5. 페이징과 정렬
  5. 6. 그룹
  6. 7. 조인
  7. 8. 서브쿼리
  8. 9. 프로젝션 결과 반환
  9.  
  10. 10. 수정, 삭제 배치 쿼리
  11. 11. 동적 쿼리
  12. 12. 메소드 위임
'자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
  • [자바 ORM 표준 JPA 프로그래밍] 13장 - 웹 애플리케이션과 영속성 관리
  • [자바 ORM 표준 JPA 프로그래밍] 12장 - 스프링 데이터 JPA
  • [자바 ORM 표준 JPA 프로그래밍] 10.2 - JPQL
  • [자바 ORM 표준 JPA 프로그래밍] 9장 - 값 타입
jny0
jny0
성장일기
J N Y 0성장일기
jny0
J N Y 0
jny0
  • 분류 전체보기 (192)
    • 트러블슈팅 (6)
    • Java (22)
    • HTML, CSS , JavaScript (7)
    • MySQL, DBMS (9)
    • GIT (6)
    • 객체지향의 사실과 오해 (3)
    • 자바 ORM 표준 JPA 프로그래밍 (13)
    • 알고리즘 (114)
      • 자료구조 (59)
      • 수학 (11)
      • 정렬 (2)
      • 그리디 (3)
      • DP (4)
      • 그래프 (3)
      • 탐색 (9)
      • 재귀 (2)
      • 문자열 (9)
      • 기타 (12)
    • CS (10)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 글쓰기
  • 관리

공지사항

인기 글

태그

  • db
  • 구현
  • git
  • DP
  • 투포인터
  • 프로그래머스
  • 영상후기
  • 백준
  • method
  • BFS
  • MySQL
  • 누적합
  • codeup
  • 자료구조
  • JS
  • JPA
  • Java
  • 그리디
  • 알고리즘
  • 스택

최근 댓글

최근 글

hELLO · Designed By 정상우.
jny0
[자바 ORM 표준 JPA 프로그래밍] 10.4 - QueryDSL
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.