Критерии Hibernate с подзапросом – использование проекции MAX и подзапросов

Вот пример использования критериев 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/

Оцените статью
Procodings.ru
Добавить комментарий