반응형
해당 강의는 코드 위주로 진행됩니다. 실질적인 객체 처리를 담당하는 코드는 링크에서 확인하시길 바랍니다.
* Criteria
- 코드로 쿼리를 구성하는 API
- JPQL 대신 자바 코드 사용
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Review> cq = cb.createQuery(Review.class);
/**
* cq를 이용해서 쿼리 구성
*/
Root<Review> root = cq.from(Review.class);
cq.select(root);
Predicate p = cb.conjunction();
if (hotelId != null) {
p = cb.and(p, cb.equal(root.get("hotelId"), hotelId));
}
p = cb.and(p, cb.greaterThan(root.get("created"), LocalDateTime.now().minusDays(10)));
if (mark >= 0) {
p = cb.and(p, cb.ge(root.get("mark"), mark));
}
cq.where(p);
cq.orderBy(cb.asc(root.get("hotelId"));
// select r from Review r where r.hotelId = 'H-001'
TypedQuery<Review> query = em.createQuery(cq); // cq를 넣어줘서 TypedQuery 형성
query.setFirstResult(4); // 0부터 시작
query.setMaxResults(4);
List<Review> reviews = query.getResultList();
* 기본 사용법
- CriteriaBuilder 생성 => CriteriaBuilder cb = em.getCriteriaBuilder();
- CreateQuery 생성 - 파라미터는 쿼리 결과 타입 => CriteriaQuery<Review> cq = cb.createQuery(Review.class);
- CQ#from 으로 from 절 엔티티 지정 - Root 타입을 이용해서 엔티티 속성 접근
=> Root<Review> root = cq.from(Review.class); - CQ#select 로 select 대상 지정 => cq.select(root);
- CE#where 로 조건 지정 - cb를 이용해서 Predicate 생성 => cq.where(cb.equal(root.get("hotelId"), "H-001"));
- CQ#orderBy로 정렬 순서 지정 - cb를 이용해서 Order 생성 => cq.orderBy(cb.asc(roote.get("id)));
- cq를 이용해서 TypedQuery 생성 => TypedQuery<Review> query = em.createQuery(cq);
* 검색 조건 지정
- CQ#where 메서드에 검색 조건 전달
- 검색 조건은 CriteriaBuilder를 이용해서 생성
- ex - 같음 조건은 CB#equal()로 생성
- 검색 조건에 사용할 엔티티 속성은 Root#get() 메서드로 구함.
Root<Review> root = cq.from(Review.class);
//생성 조건 : Review의 hotelId가 'H-001'과 같음 -> where review.hotelId = 'H-001'
Predicate predicate = cq.where(cb.equal(root.get("hotelId"), "H-001"));
cq.where(predicate);
- 조합
- CB#and, CB#or로 조건 조합
Predicate p1 = ~~~ 조건;
Predicate p2 = ~~~ 조건;
Predicate predicate = cb.and(p1, p2);
cq.where(predicate); -> where p1 and p2
* 정렬 순서 지정
- CQ#orderBy로 정렬을 지정한다.
- CB#asc(), CB#desc()로 정렬 정보(Order)를 생성한다.
- 정렬 대상 속성은 Root#get()으로 구한다.
Order orderId = cb.asc(root.get("id"));
cq.orderBy(orderId);
- 한 개 이상 정렬 지정이 가능하다.
cq.orderBy(
cb.asc(root.get("hotelId")),
cb.desc(root.get("id"))
);
* CriteriaBuilder의 주요 조건 생성 메서드
* Root#get()과 제네릭 타입
- <Y>Path<Y> get(String attributeName)
- in() 조건 생성할 때 타입 파라미터를 지정하면 유용하다.
// mark 속성(Y)이 int 타입
CriteriaBuilder.In<Object> markCond = cb.in(root.get("mark")); -> int지정을 안했으니 Object로 받음 컴파일은 되
markCond.value(1).value("a"); // Object니까 컴파일은 됨, 그러나 런타임(쿼리 생성 시점)에 에러
//mark 속성이 int 타입
CriteriaBuilder.In<Object> markCond = cb.in(root.<Integer>get("mark")); -> Integer 지정
markCond.value(1).value("a"); // 컴파일 시점에 에러
* Crietria 사용 이점
- 타입에 안전한 코드를 만들 수 있음 (위의 제네릭 타입 파라미터 예시)
- 동적인 검색 조건 지정 가능
/**
* 조건에 따라 계속해서 조건을 붙여나감
*/
Predicate p = cb.conjunction();
if (hotelId != null) {
p = cb.and(p, cb.equal(root.get("hotelId"), hotelId));
}
p = cb.and(p, cb.greaterThan(root.get("created"), LocalDateTime.now().minusDays(10)));
if (mark >= 0) {
p = cb.and(p, cb.ge(root.get("mark"), mark));
}
cq.where(p);
* 그 외 이런게 있다/된다
- JPQL과 같다.
- JPQL 함수 대신 JPA 함수를 쓸 수 있다. 하지만, 사실상 별로 사용할 일은 없다.
* 정리
- 주의 - 다음 경우는 Criteria 말고 일반 쿼리 사용 고려
- JPQL과 같다.
- 그 외
- 굳이 연관 + 쿼리를 사용하고 싶다면 N+1문제, fetch 조인을 추가로 학습하자.
- 단순하지 않은 목록 조회 / 상세 조회는 그냥 SQL을 쓰자(CQRS)
반응형
'Programming > JPA & Spring Data JPA 기초' 카테고리의 다른 글
21. Spring Data JPA 시작하기 (0) | 2023.04.06 |
---|---|
20. 기타 AttributeConverter, @Formula, @DynamicUpdate(@DynamicInsert), @Immutable, @Subselect (0) | 2023.04.05 |
18. JPQL 소개 (0) | 2023.03.30 |
17. 영속성 전파 & 연관 매핑 고려사항 (0) | 2023.03.29 |
16. 엔티티 간 1-N 단방향 연관 매핑 (0) | 2023.03.28 |
댓글