Вот пример использования критериев hibernate с подзапросами. Представим, что у нас есть приложение, которое используется для представления пользователю в пользовательском интерфейсе различных типов шаблонов афиш для различных событий. Вы можете представить, что рок-концерт будет иметь немного другую афишу, чем вечер в опере. Поэтому существует несколько типов шаблонов афиш, таких как: концерт, на открытом воздухе, пикник, театр, церковь, бег и многие другие. Пользователь может найти их все в таблице, которая показывает ему тип, дату создания, кто создал/загрузил данное изображение/плакат, и миниатюру изображения.
Таблица данных для такого продукта может выглядеть следующим образом:
Простой критериальный запрос, используемый для получения всех шаблонов постеров, должен выглядеть следующим образом
List<PosterTemplate> posters = DetachedCriteria.forClass(PosterTemplate.class)
.addOrder(Order.asc("creationDate"))
.getExecutableCriteria(entityManager.unwrap(Session.class))
.list();
На данный момент каждый из этих шаблонов может быть загружен и перезаписан/загружен пользователем.
Теперь появились новые требования к изменениям, а именно:
-
пользователь может загрузить новую версию данного типа плаката, старая версия сохраняется и хранится как старая версия
-
пользователю предоставляется последняя версия заданного типа храма
-
пользователь, нажав правой кнопкой мыши на заданном шаблоне, может увидеть его
доступные версии и выбрать/скачать их при необходимости.
Это изменение требует изменения запроса, чтобы доставить пользователям все типы шаблонов, но с числом последней/большей версии.
Прежде всего, мы добавим в базу данных новый столбец VESRION_NUMBER со значением по умолчанию 1. Каждый раз, когда пользователь загружает новый шаблон данного типа, номер версии увеличивается на единицу.
Теперь я придумал классический способ получения этих шаблонов с помощью hql. Мой запрос выглядел следующим образом:
entityManager.createQuery("select pt1 from PosterTemplate pt1 where pt1.versionNumber ="
+ " (select max(pt2.versionNumber) from PosterTemplate pt2 where pt2.type = t1.type) ",
PosterTemplate.class).getResultList();
Этот запрос дал мне то, что я хотел. Хотя у меня уже есть рабочее решение, у меня возникло искушение переписать его, используя критерии hibernate. Я, конечно, не эксперт в этой области, но мне хотелось бросить вызов самому себе и найти способ получить те же результаты, но с использованием критериев. После некоторого времени размышлений я смог прийти к такому рабочему решению:
public List<PosterTemplate> getAllPosterTemplatesWithLatestVersions() {
DetachedCriteria subCriteria = DetachedCriteria.forClass(PosterTemplate.class, "inner")
.add(Restrictions.eqProperty("inner.type", "outer.type"))
.setProjection(Projections.max("inner.versionNumber"));
return DetachedCriteria.forClass(PosterTemplate.class, "outer")
.add(Subqueries.propertyEq("outer.versionNumber", subCriteria))
.getExecutableCriteria(entityManager.unwrap(Session.class)).list();
}
Эта реализация должна дать нам такой же результат, как и тот, который был получен до использования hql.
Надеюсь, это может быть полезным для кого-то.
https://developersmill.com/