Функции за групиране и агрегиране
Вече разбрахте How да правите прости заявки към Criteria API. Нека да видим How да правим по-сложни заявки.
Например, искаме да напишем заявка за определяне на броя на служителите в една компания. Ето How ще изглежда в HQL:
select count(*) from Employee
И като това в API на критериите:
CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));
Пълният Java code ще изглежда така:
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();
И това е същото с помощта на HQL:
String hqlQuery = "select count(*) from Employee";
Query<Long> query = session.createQuery(hqlQuery);
Long count = query.getSingleResult();
Сега нека се опитаме да изчислим средната заплата в компанията. HQL заявката ще изглежда така:
select avg(salary) from Employee
И като това в API на критериите:
CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));
Пълният Java code ще изглежда така:
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();
CriteriaUpdate
Модифицирането на table е толкова лесно, колкото получаването на данни от нея. За целта CriteriaBuilder има специален метод - createCriteriaUpdate() , който създава обектCriteriaUpdate<T>Този, който актуализира обектите в базата данни.
Да вдигнем заплатите на служителите, които получават под 10 хиляди. Ето How би изглеждала тази HQL заявка:
update Employee set salary = salary+20000 where salary<=10000
Ето How ще изглежда в 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();
КритерииИзтриване
А изтриването на записи е дори по-лесно от промяната им. За целта има специален метод createCriteriaDelete() , който създава обектКритерииИзтриване<T>.
Да съкратим всички служители, които нямат стойност: заплатата им е под 10 хиляди. Ето How би изглеждала тази HQL заявка:
delete from Employee where salary<=10000
Ето How ще изглежда в 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();
Предимства на API на критериите
И така, Howва е ползата от API на критериите? Заявките са тромави, HQL определено ще бъде по-компактен.
Първо, HQL заявките не са толкова кратки, ако трябва да им подадете параметри. Сравнете:
Разглеждаме броя на служителите със заплата под 10 хиляди |
---|
HQL |
|
API за критерии |
|
Второ, много често има ситуация, когато заявката трябва да бъде конструирана динамично. Например, имате уеб page, филтрираща служители, апартаменти и всичко останало. И ако някой параметър не е важен за потребителя, той просто не го посочва. Съответно instead of това null се предава на сървъра.
Ето и вашата задача: да подберете служители с определена професия (занимание), заплата (заплата) и година на работа (YEAR (join_date)). Но ако някоя стойност на параметър е нула, тогава не я използвайте във филтъра.
Тогава HQL заявката ще изглежда така:
from Employee
where (occupation = :ocp)
and (salary = :sal)
and ( YEAR(join_date) = :jny)
Но няма да работи правилно, тъй като искаме, че ако параметърът "jny" е нулев, тогава заявката ще изглежда така:
from Employee
where (occupation = :ocp)
and (salary = :sal)
Можем да опитаме да пренапишем заявката с проверка на параметъра за нула, тогава ще получим нещо подобно:
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)
Вижте How реалността става по-сложна? Реалността често е такава :)
Но филтърът може да бъде още по-сложен. Какво ще кажете за търсене на потребители, които имат задачи с думата "купете" в тях? Или потребители, които имат просрочени задачи?
from Employee
where (occupation = :ocp)
and (salary = :sal)
and (YEAR(join_date) = :jny)
and (tasks.name like '%buy%')
and (tasks.deadline < curdate())
Ако напишете or е null някъде в такава заявка , това няма да отмени свързването между таблиците.
Така че на практика, когато правите сложен филтър върху полетата на няколко таблици, API на критериите може просто да ви помогне. Така стоят нещата.
Повече подробности можете да намерите в официалната documentация .