Criteria 쿼리는 JPQL을 자바 코드로 작성하도록 도와주는 빌더 클래스 API다.
Criteria를 사용하면 문자가 아닌 코드로 JPQL을 작성하므로 문법 오류를 컴파일 단계에서 잡을 수 있고 문자 기반의 JPQL보다 동적 쿼리를 안전하게 생성할 수 있다는 장점이 있다.
그러나 실제 Criteria를 사용해서 개발해보면 코드가 복잡하고 장황해서 직관적으로 이해가 힘들다는 단점이 있다.
//JPQL : SELECT m FROM Member mCriteriaBuilder cb = em.getCriteriaBuilder(); //Criteria쿼리 빌더 ...1//Criteria 생성, 반환 타입 지정 ...2CriteriaQuery<Member> cq = cb.createQuery(Member.class);Root<Member> m = cq.from(Member.class); //FROM 절 ...3cq.select(m); //SELECT 절 ...4TypeQuery<Member> query = em.createQuery(cq);List<Member> members = query.getResultList();
Criteria 쿼리를 생성하려면 먼저 Criteria 빌더를 얻어야 한다. Criteria 빌더는 EntityManagerFactory에서 얻을 수 있다.Criteria 쿼리 빌더에서 CriteriaQuery를 생성한다.
이때 반환 타입을 지정할 수 있다.FROM 절을 생성한다. 반환된 값 m은 Criteria에서 사용하는 특별한 별칭이다.m을 조회의 시작점이라는 의미로 쿼리 루트(Root)라 한다.SELECT 절을 생성한다.쿼리를 완성하면 다음 순서는 JPQL과 같다.
em.createQuery(cq)에 완성된 Criteria 쿼리를 넣어주기만 하면 된다.
/*****검색 조건 추가*****//*SELECT m FROM Member mWHERE m.username='회원1'ORDER BY m.age DESC*/CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Member> cq = cb.createQuery(Member.class);Root<Member> m = cq.from(Member.class);//검색 조건 정의 ...1Predicate usernameEqual = cb.equal(m.get("username"), "회원1");//정렬 조건 정의 ...2javax.persistence.criteria.Order ageDesc = cb.desc(m.get("age"));//쿼리 생성 ...3cq.select(m).where(usernameEqual).orderBy(ageDesc);List<Member> resultList = em.createQuery(cq).getResultList();
Criteria는 검색 조건부터 정렬까지 CriteriaBuilder를 사용해서 코드를 완성한다. 1. m.get("username")으로 되어 있는데 m은 회원 엔티티의 별칭이다.(=m.username)
cb.equal(A,B)는 이름 그대로 A = B라는 뜻이다.
cb.euqal(m.get("username),"회원1") == m.age desc(JPQL) 3. 만들어둔 조건을 where, orderBy에 넣어 원하는 쿼리를 생성한다.쿼리 루트(Query Root)와 별칭 - Root<Member> m = cq.from(Member.class); 여기서 m이 쿼리 루트다. - 쿼리 루트는 조회의 시작점이다. - Criteria에서 사용되는 특별한 별칭이다.(JPQL의 별칭이라 생각하면 됨) - 별칭은 엔티티에만 부여할 수 있다.
Criteria 경로 표현식 - m.get("username") JPQL의 m.username과 같다. - m.get("team").get("name")은 JPQL의 m.team.name과 같다.
//10살을 초과하는 회원을 조회하고 나이 역순으로 정렬/*SELECT m FROM Member mWHERE m.age > 10ORDER BY m.age DESC*/Root<Member> m = cq.from(Member.class);//타입 정보 필요Predicate ageGt = cb.greaterThan(m.<Integer>get("age"), 10); //==cb.gt();cq.select(m);cq.where(ageGt);cq.orderBy(cb.desc(m.get("age")));