通过在 Hibernate 中打开 SQL 调试并比较生成的查询,可以非常清楚地看到这里发生了什么。
使用相当简单的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
像这样:
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
like是一个Java 类,它在 SQL 执行后DISTINCT_ROOT_ENTITY
处理 SQL 行的结果。因此,当您指定 a时,它将作为 SQL 的行限制应用;SQL 包括对 中元素的连接,因此您将 SQL 结果限制为 90个子元素。一旦应用了转换器,这可能会导致少于 20 个根元素,这完全取决于在 90 个连接结果中哪些根元素碰巧首先出现。maxResults
Collection
DISTINCT_ROOT_ENTITY
DISTINCT
在 HQL 中的行为非常不同,因为它实际上使用了 SQLDISTINCT
关键字,该关键字应用在行限制之前。因此,它的行为与您预期的一样,并解释了 2 之间的区别。
从理论上讲,您应该考虑在setProjection
SQL 级别应用投影——类似的东西c.setProjection(Projections.distinct(Projections.rootEntity()))
——但不幸Projections.rootEntity()
的是不存在,我只是编造的。也许应该!