Funções de agrupamento e agregação

Você já descobriu como fazer solicitações simples para a Criteria API. Vamos ver como fazer consultas mais complexas.

Por exemplo, queremos escrever uma consulta para determinar o número de funcionários de uma empresa. Veja como ficará em HQL:

select count(*) from Employee

E assim na Criteria API:

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

O código Java completo ficará assim:

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();

E é o mesmo usando HQL:

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

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

Agora vamos tentar calcular o salário médio na empresa. A consulta HQL ficará assim:

select avg(salary) from Employee

E assim na Criteria API:

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

O código Java completo ficará assim:

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();

CriteriaUpdate

Modificar uma tabela é tão fácil quanto obter dados dela. Para fazer isso, o CriteriaBuilder possui um método especial - createCriteriaUpdate() , que cria um objetoCriteriaUpdate<T>O que atualiza as entidades no banco de dados.

Vamos aumentar o salário dos funcionários que recebem menos de 10 mil. Veja como seria esta consulta HQL:

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

E é assim que ficará na 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();

CritériosExcluir

E excluir registros é ainda mais fácil do que alterá-los. Para fazer isso, existe um método especial createCriteriaDelete() , que cria um objetoCritériosExcluir<T>.

Vamos cortar todos os funcionários que não têm valor: o salário deles é inferior a 10 mil. Veja como seria esta consulta HQL:

delete from Employee where salary<=10000

E é assim que ficará na 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();

Benefícios da API de critérios

Então, qual é o benefício da Criteria API? As consultas são complicadas, o HQL com certeza será mais compacto.

Em primeiro lugar, as consultas HQL não são tão curtas se você precisar passar parâmetros para elas. Comparar:

Consideramos o número de colaboradores com salário inferior a 10 mil
HQL
String hqlQuery = "from Employee where salary < :sal";
Query<Employee> query = session.createQuery(hqlQuery);
query.setParametr("sal", 10000);
List<Employee> results = query.getResultList();
API de critérios
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();

Em segundo lugar, muitas vezes há uma situação em que uma consulta precisa ser construída dinamicamente. Por exemplo, você tem uma página da web filtrando funcionários, apartamentos e qualquer coisa. E se algum parâmetro não for importante para o usuário, ele simplesmente não o indica. Da mesma forma, null é passado para o servidor.

Aqui está sua tarefa: selecionar funcionários com uma determinada profissão (ocupação), salário (salário) e ano de trabalho (YEAR (join_date)). Mas se algum valor de parâmetro for nulo, não o use no filtro.

Então a consulta HQL ficará mais ou menos assim:

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

Mas não funcionará corretamente, pois queremos que, se o parâmetro "jny" for nulo, a solicitação fique assim:

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

Podemos tentar reescrever a solicitação verificando se o parâmetro é nulo, então obteremos algo assim:

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)

Vê como a realidade fica mais complicada? A realidade costuma ser assim :)

Mas o filtro pode ser ainda mais complicado. Que tal procurar usuários que tenham tarefas com a palavra "comprar"? Ou usuários com tarefas atrasadas?

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

Se você escrever ou for nulo em algum lugar dessa consulta , isso não cancelará a junção entre as tabelas.

Então, na prática, quando você faz qualquer filtro complexo nos campos de várias tabelas, a API Criteria pode te ajudar. Assim vai.

Mais detalhes podem ser encontrados na documentação oficial .