Funcții de grupare și agregare

V-ați dat deja seama cum să faceți solicitări simple către API-ul Criteria. Să vedem cum să facem interogări mai complexe.

De exemplu, dorim să scriem o interogare pentru a determina numărul de angajați dintr-o companie. Iată cum va arăta în HQL:

select count(*) from Employee

Și așa în API-ul Criteria:

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

Codul Java complet va arăta astfel:

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

Și este același lucru folosind HQL:

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

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

Acum să încercăm să calculăm salariul mediu în companie. Interogarea HQL va arăta astfel:

select avg(salary) from Employee

Și așa în API-ul Criteria:

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

Codul Java complet va arăta astfel:

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

CriteriiUpdate

Modificarea unui tabel este la fel de simplă precum obținerea datelor din acesta. Pentru a face acest lucru, CriteriaBuilder are o metodă specială - createCriteriaUpdate() , care creează un obiectCriteriaUpdate<T>Cel care actualizează entitățile din baza de date.

Să creștem salariul angajaților care primesc mai puțin de 10 mii. Iată cum ar arăta această interogare HQL:

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

Și așa va arăta în API-ul Criteria:

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

CriteriiDelete

Și ștergerea înregistrărilor este chiar mai ușoară decât schimbarea lor. Pentru a face acest lucru, există o metodă specială createCriteriaDelete() , care creează un obiectCriteriiDelete<T>.

Să tăiem toți angajații care nu au valoare: salariul lor este mai mic de 10 mii. Iată cum ar arăta această interogare HQL:

delete from Employee where salary<=10000

Și așa va arăta în API-ul Criteria:

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

Beneficiile API-ului Criteria

Deci, care este beneficiul API-ului Criteria? Interogările sunt greoaie, HQL va fi cu siguranță mai compact.

În primul rând, interogările HQL nu sunt atât de scurte dacă trebuie să le transmiteți parametri. Comparaţie:

Luăm în considerare numărul de angajați cu un salariu mai mic de 10 mii
HQL
String hqlQuery = "from Employee where salary < :sal";
Query<Employee> query = session.createQuery(hqlQuery);
query.setParametr("sal", 10000);
List<Employee> results = query.getResultList();
Criterii 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();

În al doilea rând, de foarte multe ori există o situație în care o interogare trebuie să fie construită dinamic. De exemplu, aveți o pagină web care filtrează angajați, apartamente și orice altceva. Și dacă un parametru nu este important pentru utilizator, atunci pur și simplu nu îl indică. În consecință, null este transmis serverului.

Iată sarcina dvs.: să selectați angajați cu o anumită profesie (ocupație), salariu (salariu) și anul de angajare (AN (ANUL (join_date))). Dar dacă orice valoare a parametrului este nulă, atunci nu o utilizați în filtru.

Apoi interogarea HQL va arăta cam așa:

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

Dar nu va funcționa corect, deoarece dorim ca dacă parametrul „jny” a fost nul, atunci cererea să arate astfel:

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

Putem încerca să rescriem cererea cu verificarea parametrului pentru null, apoi vom obține ceva de genul acesta:

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)

Vezi cum realitatea devine mai complicată? Realitatea este adesea așa :)

Dar filtrul poate fi și mai complicat. Ce zici de a căuta utilizatori care au sarcini cu cuvântul „cumpără” în ele? Sau utilizatori care au sarcini restante?

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

Dacă scrieți sau este null undeva într-o astfel de interogare , atunci aceasta nu va anula îmbinarea dintre tabele.

Deci, în practică, atunci când faceți orice filtru complex pe câmpurile mai multor tabele, API-ul Criteria vă poate ajuta. Așa merge.

Mai multe detalii găsiți în documentația oficială .