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 |
|
API de critérios |
|
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 .
GO TO FULL VERSION