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());
}
  1. Criteria 쿼리를 생성하려면 먼저 Criteria 빌더를 얻어야 한다.
  2. Criteria 빌더에서 Criteria 쿼리를 생성한다.
  3. FROM절을 생성한다. 반환값은 특별한 쿼리 ROOT
  4. 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

결과

results matching ""

    No results matching ""