Criteria
JPQL을 자바 코드로 작성하도록 도와주는 빌더 클래스 API
장점
- 문법 오류를 컴파일 단계에서 잡아준다.
단점
- 코드가 복잡하고 장황해서 직관적으로 이해하기가 힘들다.
10.3.1 Criteria 기초
Criteria API는 javax.persistence.criteria 패키지에 있다.
Criteria 쿼리 시작
//JPQL : select m from Member m
CriteriaBuilder cb = em.getCriteriaBuilder();
//Criteria 생성, 반환 타입 지정
CriteriaQuery<Member> cq = cb.createQuery(Member.class);
Root<Member> m = cq.from(Member.class); // FROM 절
cq.select(m); // SELECT 절
TypedQuery<Member> query = em.createQuery(cq);
List<Member> resultList = query.getResultList();
System.out.println("**************");
for (Member member : resultList) {
System.out.println("member id = " + member.getId() + ", member name = " + member.getUsername());
}
- Criteria 쿼리를 생성하려면 먼저 Criteria 빌더를 얻어야 한다.
- Criteria 빌더에서 Criteria 쿼리를 생성한다.
- FROM절을 생성한다. 반환값은 특별한 쿼리 ROOT
- SELECT 절을 생성한다.
검색 조건과 정렬 추가
CriteriaBuilder cb = em.getCriteriaBuilder();
//Criteria 생성, 반환 타입 지정
CriteriaQuery<Member> cq = cb.createQuery(Member.class);
Root<Member> m = cq.from(Member.class); // FROM 절
//검색 조건 정의
Predicate usernameEquals = cb.equal(m.get("username"), "지한");
//정렬 조건 정의
javax.persistence.criteria.Order ageDesc = cb.desc(m.get("age"));
//쿼리 생성
cq.select(m)
.where(usernameEquals)
.orderBy(ageDesc);
List<Member> resultList = em.createQuery(cq).getResultList();
System.out.println("**************");
for (Member member : resultList) {
System.out.println("member id = " + member.getId() + ", member name = " + member.getUsername());
}
반환 타입을 지정할 수 없거나 반환 타입이 둘 이상
Object로 반환
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Object> cq = cb.createQuery(); // 조회 반환 타입 : Object
...
List<Object> resultList = em.createQuery(cq).getResultList();
Object[]로 반환
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class); // 조회 반환 타입 : Object
...
List<Object[]> resultList = em.createQuery(cq).getResultList();
튜플로 조회
이름 기반으로 순서 기반의 Object[]보다 안전하다.
CriteriaBuilder cb = em.getCriteriaBuilder();
// 조회값 반환 타입 : Tuple
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
...
TypedQuery<Tuple> query = em.createQuery(cq);
튜플 예제코드
CriteriaBuilder cb = em.getCriteriaBuilder();
//Criteria 생성, 반환 타입 지정
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Member> m = cq.from(Member.class); // FROM 절
//검색 조건 정의
Predicate usernameEquals = cb.equal(m.get("username"), "지한");
//정렬 조건 정의
javax.persistence.criteria.Order ageDesc = cb.desc(m.get("age"));
//쿼리 생성
cq.select(
cb.tuple(m.alias("m"), m.get("username").alias("username")))
.where(usernameEquals)
.orderBy(ageDesc);
List<Tuple> resultList = em.createQuery(cq).getResultList();
System.out.println("**************");
for (Tuple tuple : resultList) {
Member member = tuple.get("m", Member.class);
String username = tuple.get("username", String.class);
System.out.println("member id = " + member.getId() + ", member name = " + member.getUsername() + ", " + username);
}
조인
join() 메소드와 JoinType 클래스를 사용한다.
public enum JoinType {
INNER, //내부조인
LEFT, //왼쪽 외부 조인
RIGHT //오른쪽 외부 조인, 지원하지 않을 수 있음
}
조인 예제
/* JPQL
select m, t from Member m
inner join m.team t
where t.name = '팀A'
*/
Root<Member> m = cq.from(Member.class);
Join<Member, Team> t = m.join("team", JoinType.INNER); // 내부조인
cq.multiselect(m, t)
.where(cb.equal(t.get("name"), "팀A"));
Criteria 메타 모델 API
Criteria는 코드 기반으로 컴파일시 오류를 발견.
그러나 m.get("age")의 "age"는 문자. 오타가 있는 경우 컴파일 시점에 발견 못함.
완전한 코드 기반으로 작성하려면 메타 모델 API 사용
- 메타 모델 적용 전
cq.select(m) .where(cb.gt(m.<Integer>get("username"), 20)) .orderBy(cb.desc(m.get("age")));
- 메타 모델 적용 후
cq.select(m) .where(cb.gt(Mebmer_.age), 20)) .orderBy(cb.desc(m.get(Member_.age)));
Member_ 메타 모델 클래스는 Member 엔티티를 기반으로 만들어야 한다.
개발자가 직접 만들지 않음.
코드 자동 생성기가 엔티티 클래스를 기반으로 메타 모델 클래스르 만들어 준다.
하이버네이트 코드 생성기
org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor
코드 생성기 MAVEN 설정
// pom.xml <dependencies> 안에
<!-- 메타모델 생성기 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>1.3.0.Final</version>
</dependency>
// pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArguments>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
코드 자동 생성
mvn compile