Есть ли лучший способ, чем использовать DetachedCriteria для нумерации страниц?

Сортировка и разбиение по страницам с помощью API Criteria api Hibernate имеет большое ограничение, оно требует извлечения отдельных результатов из базы данных. Инструменты, предоставляемые API, такие как DistinctRootTransformer, не будут работать, потому что он применяется после извлечения сущностей из БД и, таким образом, нарушает разбиение на страницы и сортировку. Единственный способ получить отчетливые результаты запроса с ограничениями на сопоставление - это ограничение результирующего набора с помощью DetachedCriteria:

DetachedCriteria dc = DetachedCriteria.forClass(Household.class, "h")
                .createAlias("cats", "c", JoinType.LEFT_OUTER_JOIN)
                .add(Restrictions.or(
                        Restrictions.isEmpty("cats"),
                        Restrictions.ne("c.name", "Sylvester")
                ))
                .setProjection(Projections.distinct(Projections.property("h.id")));

Criteria criteria = session.createCriteria(Household.class)
                .add(Property.forName("id").in(dc));

...apply paging, sorting and filtering to criteria.

Кто-нибудь знает лучший подход, такой как пропуск подзапросов и использование объединений без разбиения на страницы? Моя цель - найти решение, которое можно использовать повторно, например, передать только критерии другому методу, который применяет разбиение на страницы, сортировку и фильтрацию.

Обновить:

Следующий код не работает. Из-за объединения я должен использовать Resulttransformer, чтобы получить отличные результаты. Однако он применяется после сортировки и подкачки.

Criteria criteria = session.createCriteria(Household.class)
   .createAlias("cats", "c", JoinType.LEFT_OUTER_JOIN)
   .add(Restrictions.ne("c.name","Sylvester"))
   .setFirstResult((page - 1) * pagesize)
   .setMaxResults(pagesize)
   .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

Например, отладка sql базы данных выдаст что-то вроде этого:

household_id = 1,... cat_ids = {1,2}; household_id = 1,... cat_ids = {1,2}; household_id = 2,... cat_ids = {1};

В этом примере установка размера страницы в 1 и просмотр страницы 2 должны вернуть uid 2, потому что есть только два разных пользователя. Но, как вы можете видеть в выходных данных базы данных, он возвращает неправильный uid 1, потому что Resulttransformers запускается впоследствии.

2 ответа

Если вы создаете DetachedCriteria в каком-либо методе, а затем работаете с ним, вы можете попытаться преобразовать DetachedCriteria в Criteria, используя что-то вроде:

DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Your.class);
// then add all your restrictions and convert
Criteria criteria = detachedCriteria.getExecutableCriteria(session);

А потом примените пагинацию

criteria.setFirstResult(pageable.getPage() * pageable.getSize());
criteria.setMaxResults(pageable.getSize());

А затем выполнить критерии. Например:

List<T> result = criteria.list();

Когда мне нужно разбить на страницы, я никогда не использую DetachedCriteria, а вместо этого обычные Criteria, контролирующие первый и максимальный результаты.

По виду я определяю, какую страницу мне нужно показать, и после того, как я подготовил критерии, я настраиваю его следующим образом:

criteria.setMaxResults(lazyQuery.getPageSize());
criteria.setFirstResult(layQuery.getStart());

lazyQuery это объект моей собственной модели, используемый для представления и бизнес-логики. Это работает отлично.

Другие вопросы по тегам