Funciones de agrupación y agregación

Ya descubrió cómo realizar solicitudes simples a la API de Criteria. Veamos cómo hacer consultas más complejas.

Por ejemplo, queremos escribir una consulta para determinar el número de empleados en una empresa. Así es como se verá en HQL:

select count(*) from Employee

Y así en la API de Criteria:

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

El código Java completo se verá así:

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

Y es lo mismo usando HQL:

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

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

Ahora intentemos calcular el salario promedio en la empresa. La consulta HQL se verá así:

select avg(salary) from Employee

Y así en la API de Criteria:

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

El código Java completo se verá así:

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

Actualización de criterios

Modificar una tabla es tan fácil como obtener datos de ella. Para hacer esto, CriteriaBuilder tiene un método especial - createCriteriaUpdate() , que crea un objetoActualización de criterios<T>que actualiza las entidades en la base de datos.

Subamos el sueldo de los empleados que cobran menos de 10 mil. Así es como se vería esta consulta HQL:

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

Y así es como se verá en la API de criterios:

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

Criterios Eliminar

Y borrar registros es incluso más fácil que cambiarlos. Para ello, existe un método especial createCriteriaDelete() , que crea un objetoCriteriosEliminar<T>.

Recortemos a todos los empleados que no tienen ningún valor: su salario es inferior a 10 mil. Así es como se vería esta consulta HQL:

delete from Employee where salary<=10000

Y así es como se verá en la API de criterios:

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

Beneficios de la API de Criterios

Entonces, ¿cuál es el beneficio de la API de Criteria? Las consultas son engorrosas, HQL definitivamente será más compacto.

En primer lugar, las consultas HQL no son tan cortas si necesita pasarles parámetros. Comparar:

Consideramos el número de empleados con un salario 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 criterios
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();

En segundo lugar, muy a menudo hay una situación en la que una consulta debe construirse dinámicamente. Por ejemplo, tiene una página web que filtra empleados, apartamentos y cualquier cosa. Y si algún parámetro no es importante para el usuario, simplemente no lo indica. En consecuencia, se pasa null al servidor en su lugar.

Aquí está su tarea: seleccionar empleados con cierta profesión (ocupación), salario (salario) y año de empleo (AÑO (join_date)). Pero si algún valor de parámetro es nulo, no lo use en el filtro.

Entonces la consulta HQL se verá así:

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

Pero no funcionará correctamente, ya que queremos que si el parámetro "jny" fuera nulo, entonces la solicitud se vería así:

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

Podemos intentar reescribir la solicitud verificando el parámetro para nulo, luego obtendremos algo como esto:

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)

¿Ves cómo la realidad se vuelve más complicada? La realidad es a menudo así :)

Pero el filtro puede complicarse aún más. ¿Qué tal buscar usuarios que tengan tareas con la palabra "comprar" en ellas? ¿O usuarios que tienen tareas atrasadas?

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

Si escribe o es nulo en algún lugar de dicha consulta , esto no cancelará la unión entre tablas.

Entonces, en la práctica, cuando realiza un filtro complejo en los campos de varias tablas, la API de criterios puede ayudarlo. Así que va.

Se pueden encontrar más detalles en la documentación oficial .