Критерии API возвращают слишком небольшой набор результатов

Как это возможно, я имею к следующим критериям

Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();

Размер списка равняется теперь 20. Если я добавляю макс. результаты к критериям,

Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setMaxResults(90);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();

.. теперь размер списка равняется 18!

Я не понимаю, как размер наборов результатов может быть меньшим после определения макс. результатов, как сумма строк меньше, чем определенный максимум. Это уверенное походит на ошибку или там снова, некоторые странные аспекты в спящем режиме, о котором я не знаю?


При поиске ответа на этот вопрос удостоверьтесь, что прочитали принятый ответ и его комментарии.

14
задан Mikko Maunu 25 August 2013 в 17:35
поделиться

2 ответа

То, что здесь происходит, можно очень ясно увидеть, включив отладку SQL в Hibernate и сравнив сгенерированные запросы.

Используя довольно простой Sale Item сопоставление «один ко многим» (которое, надеюсь, не требует пояснений), запрос на основе Criteria , подобный этому :

Criteria c = sessionFactory.getCurrentSession().createCriteria(Sale.class);
c.createAlias("items", "i");
c.add(Restrictions.eq("i.name", "doll"));
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.setMaxResults(2);

производит такой SQL:

select top ? this_.saleId as saleId1_1_, ... 
from Sale this_ 
inner join Sale_Item items3_ on this_.saleId=items3_.Sale_saleId 
inner join Item items1_ on items3_.items_id=items1_.id 
where items1_.name=?

, тогда как Запрос вроде этого:

Query q = sessionFactory.getCurrentSession().createQuery("select distinct s from Sale s join s.items as i where i.name=:name");
q.setParameter("name", "doll");
q.setMaxResults(2);

производит что-то вроде:

select top ? distinct hibernated0_.saleId as saleId1_ 
from Sale hibernated0_ 
inner join Sale_Item items1_ on hibernated0_.saleId=items1_.Sale_saleId 
inner join Item hibernated2_ on items1_.items_id=hibernated2_.id 
where hibernated2_.name=?

Обратите внимание на разницу в самой первой строке ( DISTINCT ). ResultTransformer как DISTINCT_ROOT_ENTITY - это класс Java, который обрабатывает результаты строк SQL после выполнения SQL.Следовательно, когда вы указываете maxResults , это будет применяться как ограничение строки в SQL; SQL включает объединение элементов в коллекции , поэтому вы ограничиваете свой результат SQL до 90 подэлементов . После применения преобразователя DISTINCT_ROOT_ENTITY это может привести к менее чем 20 корневым элементам, в зависимости от того, какие корневые элементы оказываются первыми в 90 объединенных результатах.

DISTINCT в HQL ведет себя совершенно иначе, поскольку фактически использует ключевое слово SQL DISTINCT , которое применяется перед ограничением строки. Следовательно, это ведет себя так, как вы ожидаете, и объясняет разницу между 2.

Теоретически вы должны посмотреть на setProjection , чтобы применить проекцию на уровне SQL - что-то вроде c. setProjection (Projection.distinct (Projection.rootEntity ())) - но, к сожалению, Projection.rootEntity () не существует, я просто придумал.Возможно, стоит!

9
ответ дан 1 December 2019 в 14:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: