Funkcje grupujące i agregujące

Wiesz już, jak wysyłać proste żądania do API kryteriów. Zobaczmy, jak tworzyć bardziej złożone zapytania.

Na przykład chcemy napisać zapytanie, aby określić liczbę pracowników w firmie. Oto jak to będzie wyglądać w HQL:

select count(*) from Employee

I tak w interfejsie API kryteriów:

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

Cały kod Java będzie wyglądał następująco:

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 tak samo jest przy użyciu HQL:

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

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

Spróbujmy teraz obliczyć średnie wynagrodzenie w firmie. Zapytanie HQL będzie wyglądać następująco:

select avg(salary) from Employee

I tak w interfejsie API kryteriów:

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

Cały kod Java będzie wyglądał następująco:

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

Aktualizacja kryteriów

Modyfikowanie tabeli jest tak proste, jak pobieranie z niej danych. W tym celu CriteriaBuilder posiada specjalną metodę - createCriteriaUpdate() , która tworzy obiektCriteriaUpdate<T>To aktualizuje podmioty w bazie danych.

Podnieśmy pensje pracownikom, którzy otrzymują mniej niż 10 tys. Oto jak wyglądałoby to zapytanie HQL:

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

A tak to będzie wyglądać w 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();

KryteriaUsuń

A usuwanie rekordów jest jeszcze łatwiejsze niż ich zmiana. Służy do tego specjalna metoda createCriteriaDelete() , która tworzy obiektKryteriaDelete<T>.

Odetnijmy wszystkich pracowników, którzy nie mają żadnej wartości: ich pensja to mniej niż 10 tys. Oto jak wyglądałoby to zapytanie HQL:

delete from Employee where salary<=10000

A tak to będzie wyglądać w 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();

Korzyści z interfejsu API kryteriów

Jaka jest zatem korzyść z API Criteria? Zapytania są uciążliwe, HQL na pewno będzie bardziej zwarty.

Po pierwsze, zapytania HQL nie są takie krótkie, jeśli trzeba przekazać im parametry. Porównywać:

Bierzemy pod uwagę liczbę pracowników z pensją poniżej 10 tys
HQL
String hqlQuery = "from Employee where salary < :sal";
Query<Employee> query = session.createQuery(hqlQuery);
query.setParametr("sal", 10000);
List<Employee> results = query.getResultList();
API kryteriów
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();

Po drugie, bardzo często zdarza się, że zapytanie musi być skonstruowane dynamicznie. Na przykład masz stronę internetową filtrującą pracowników, mieszkania i wszystko. A jeśli jakiś parametr nie jest dla użytkownika ważny, to po prostu go nie wskazuje. W związku z tym zamiast tego do serwera przekazywana jest wartość null.

Oto Twoje zadanie: wybrać pracowników z określonym zawodem (zawodem), wynagrodzeniem (pensal) i rokiem zatrudnienia (ROK (join_date)). Ale jeśli jakakolwiek wartość parametru jest pusta, nie używaj jej w filtrze.

Wtedy zapytanie HQL będzie wyglądać mniej więcej tak:

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

Ale to nie będzie działać poprawnie, ponieważ chcemy, aby jeśli parametr „jny” był pusty, żądanie wyglądałoby tak:

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

Możemy spróbować przepisać żądanie ze sprawdzeniem parametru na null, wtedy otrzymamy coś takiego:

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)

Widzisz, jak rzeczywistość staje się bardziej skomplikowana? Rzeczywistość często tak wygląda :)

Ale filtr może być jeszcze bardziej skomplikowany. Co powiesz na wyszukiwanie użytkowników, którzy mają zadania ze słowem „kup”? Lub użytkowników, którzy mają zaległe zadania?

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

Jeśli napiszesz lub jest null gdzieś w takim zapytaniu , nie spowoduje to anulowania łączenia między tabelami.

Tak więc w praktyce, gdy wykonujesz skomplikowany filtr pól kilku tabel, interfejs Criteria API może ci po prostu pomóc. Tak to idzie.

Więcej szczegółów można znaleźć w oficjalnej dokumentacji .