그룹화 및 집계 기능

Criteria API에 간단한 요청을 하는 방법을 이미 알아냈습니다. 더 복잡한 쿼리를 만드는 방법을 살펴보겠습니다.

예를 들어 회사의 직원 수를 확인하는 쿼리를 작성하려고 합니다. HQL에서는 다음과 같이 표시됩니다.

select count(*) from Employee

그리고 Criteria API에서는 다음과 같습니다.

CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));

완전한 Java 코드는 다음과 같습니다.

CriteriaBuilder builder = session.getCriteriaBuilder();

CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));

Query<Long> query = session.createQuery(critQuery);
Long count = query.getSingleResult();

HQL을 사용해도 마찬가지입니다.

String hqlQuery = "select count(*) from Employee";

Query<Long> query = session.createQuery(hqlQuery);
Long count = query.getSingleResult();

이제 회사의 평균 급여를 계산해 봅시다. HQL 쿼리는 다음과 같습니다.

select avg(salary) from Employee

그리고 Criteria API에서는 다음과 같습니다.

CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));

완전한 Java 코드는 다음과 같습니다.

CriteriaBuilder builder = session.getCriteriaBuilder();

CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));

Query<Double> query = session.createQuery(critQuery);
Double avgSalary = query.getSingleResult();

기준 업데이트

테이블 수정은 테이블에서 데이터를 가져오는 것만큼 쉽습니다. 이를 위해 CriteriaBuilder에는 객체를 생성하는 createCriteriaUpdate() 라는 특수 메서드가 있습니다.기준 업데이트<T>데이터베이스의 엔터티를 업데이트하는 입니다.

10,000 미만을받는 직원의 급여를 인상합시다. 이 HQL 쿼리는 다음과 같습니다.

update Employee set salary = salary+20000 where salary<=10000

Criteria API에서는 다음과 같이 표시됩니다.

CriteriaUpdate<Employee> criteriaUpdate = builder.createCriteriaUpdate(Employee.class);
Root<Employee> root = criteriaUpdate.from(Employee.class);
criteriaUpdate.set("salary", "salary+20000");
criteriaUpdate.where(builder.lt(root.get("salary"), 10000));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaUpdate).executeUpdate();
transaction.commit();

기준삭제

레코드를 삭제하는 것이 변경하는 것보다 훨씬 쉽습니다. 이를 위해 객체를 생성하는 createCriteriaDelete() 특수 메서드가 있습니다.기준삭제<T>.

가치가 없는 모든 직원을 삭감합시다. 급여가 10,000 미만입니다. 이 HQL 쿼리는 다음과 같습니다.

delete from Employee where salary<=10000

Criteria API에서는 다음과 같이 표시됩니다.

CriteriaDelete<Employee> criteriaDelete = builder.createCriteriaDelete(Employee.class);
Root<Employee> root = criteriaDelete.from(Employee.class);
criteriaDelete.where(builder.lt(root.get("salary"), 10000));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaDelete).executeUpdate();
transaction.commit();

Criteria API의 이점

그렇다면 Criteria API의 이점은 무엇입니까? 쿼리는 번거롭습니다. HQL은 확실히 더 컴팩트할 것입니다.

첫째, 매개변수를 전달해야 하는 경우 HQL 쿼리는 그렇게 짧지 않습니다. 비교하다:

급여가 10,000 미만인 직원 수를 고려합니다.
HQL
String hqlQuery = "from Employee where salary < :sal";
Query<Employee> query = session.createQuery(hqlQuery);
query.setParametr("sal", 10000);
List<Employee> results = query.getResultList();
기준 API
CriteriaBuilder builder = session.getCriteriaBuilder();
critQuery.select(critQuery.from(Employee.class)).where(builder.lt(root.get("salary"), 10000));
Query<Employee> query = session.createQuery(critQuery);
List<Employee> results = query.getResultList();

둘째, 쿼리를 동적으로 구성해야 하는 상황이 자주 발생합니다. 예를 들어 직원, 아파트 등을 필터링하는 웹 페이지가 있습니다. 일부 매개 변수가 사용자에게 중요하지 않은 경우 단순히 표시하지 않습니다. 따라서 대신 서버에 null이 전달됩니다.

귀하의 임무는 다음과 같습니다. 특정 직업(직업), 급여(급여) 및 고용 연도(YEAR(join_date))를 가진 직원을 선택하는 것입니다. 그러나 매개 변수 값이 null이면 필터에서 사용하지 마십시오.

그러면 HQL 쿼리는 다음과 같이 표시됩니다.

from Employee
where (occupation = :ocp)
   	and (salary = :sal)
   	and ( YEAR(join_date) = :jny)

그러나 "jny" 매개변수가 null인 경우 요청이 다음과 같기를 원하기 때문에 올바르게 작동하지 않습니다.

from Employee
where (occupation = :ocp)
   	and (salary = :sal)

null에 대한 매개 변수를 확인하여 요청을 다시 작성할 수 있습니다. 그러면 다음과 같은 결과가 나타납니다.

from Employee
where (occupation = :ocp or :ocp is null)
   	and (salary = :sal or :sal is null)
   	and ( YEAR(join_date)= :jny or :jny is null)

현실이 어떻게 더 복잡해지는지 보십니까? 현실은 종종 이렇습니다 :)

그러나 필터는 훨씬 더 복잡할 수 있습니다. "구매"라는 단어가 포함된 작업이 있는 사용자를 검색하는 것은 어떻습니까? 아니면 기한이 지난 사용자입니까?

from Employee
where (occupation = :ocp)
   	and (salary = :sal)
   	and (YEAR(join_date) = :jny)
   	and (tasks.name like '%buy%')
   	and (tasks.deadline < curdate())

그러한 쿼리 어딘가에 쓰거나 null이면 테이블 간의 조인이 취소되지 않습니다.

따라서 실제로 여러 테이블의 필드에 대해 복잡한 필터를 수행할 때 Criteria API가 도움이 될 수 있습니다. 그래서 간다.

자세한 내용은 공식 문서 에서 확인할 수 있습니다 .