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 |
|
API kryteriów |
|
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 .
GO TO FULL VERSION