Grupperings- og aggregeringsfunktioner

Du har allerede fundet ud af, hvordan du laver enkle anmodninger til Criteria API. Lad os se, hvordan man laver mere komplekse forespørgsler.

For eksempel vil vi skrive en forespørgsel for at bestemme antallet af ansatte i en virksomhed. Sådan vil det se ud i HQL:

select count(*) from Employee

Og sådan her på Criteria API:

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

Den komplette Java-kode vil se sådan ud:

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

Og det er det samme med HQL:

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

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

Lad os nu prøve at beregne den gennemsnitlige løn i virksomheden. HQL-forespørgslen vil se sådan ud:

select avg(salary) from Employee

Og sådan her på Criteria API:

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

Den komplette Java-kode vil se sådan ud:

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

Opdatering af kriterier

Det er lige så nemt at ændre en tabel som at hente data fra den. For at gøre dette har CriteriaBuilder en speciel metode - createCriteriaUpdate() , som opretter et objektCriteriaUpdate<T>Den der opdaterer entiteterne i databasen.

Lad os hæve lønnen for medarbejdere, der modtager mindre end 10 tusind. Sådan ser denne HQL-forespørgsel ud:

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

Og sådan vil det se ud på 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();

Kriterier Slet

Og det er endnu nemmere at slette poster end at ændre dem. For at gøre dette er der en speciel metode createCriteriaDelete() , som opretter et objektKriterier Slet<T>.

Lad os skære alle ansatte, der ikke har nogen værdi: deres løn er mindre end 10 tusind. Sådan ser denne HQL-forespørgsel ud:

delete from Employee where salary<=10000

Og sådan vil det se ud på 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();

Fordele ved Criteria API

Så hvad er fordelen ved Criteria API? Forespørgsler er besværlige, HQL vil helt sikkert være mere kompakt.

For det første er HQL-forespørgsler ikke så korte, hvis du skal sende parametre til dem. Sammenligne:

Vi betragter antallet af medarbejdere med en løn på mindre end 10 tusind
HQL
String hqlQuery = "from Employee where salary < :sal";
Query<Employee> query = session.createQuery(hqlQuery);
query.setParametr("sal", 10000);
List<Employee> results = query.getResultList();
Kriterier 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();

For det andet er der meget ofte en situation, hvor en forespørgsel skal konstrueres dynamisk. For eksempel har du en webside, der filtrerer medarbejdere, lejligheder og andet. Og hvis en eller anden parameter ikke er vigtig for brugeren, angiver han det simpelthen ikke. Derfor sendes null til serveren i stedet.

Her er din opgave: at udvælge medarbejdere med et bestemt erhverv (beskæftigelse), løn (løn) og ansættelsesår (ÅR (join_date)). Men hvis en parameterværdi er null, skal du ikke bruge den i filteret.

Så vil HQL-forespørgslen se sådan ud:

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

Men det vil ikke fungere korrekt, da vi ønsker, at hvis "jny" parameteren var null, så ville anmodningen se sådan ud:

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

Vi kan prøve at omskrive anmodningen med at kontrollere parameteren for null, så får vi noget som dette:

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)

Se, hvordan virkeligheden bliver mere kompliceret? Virkeligheden er ofte sådan :)

Men filteret kan være endnu mere kompliceret. Hvad med at søge efter brugere, der har opgaver med ordet "køb" i sig? Eller brugere, der har forfaldne opgaver?

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

Hvis du skriver eller er null et sted i en sådan forespørgsel , vil dette ikke annullere sammenkædningen mellem tabeller.

Så i praksis, når du laver et komplekst filter på felterne i flere tabeller, kan Criteria API bare hjælpe dig. Sådan går det.

Flere detaljer kan findes i den officielle dokumentation .