Java Criteria API返回的结果集太小
这怎么可能,我必须遵循以下标准Java Criteria API返回的结果集太小,java,hibernate,criteria,hibernate-criteria,Java,Hibernate,Criteria,Hibernate Criteria,这怎么可能,我必须遵循以下标准 Criteria criteria = getSession().createCriteria(c); criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); criteria.add(Restrictions.eq("active",true)); List list = criteria.list(); 列表的大小现在是20。如果我在标准中添加一个max results Criteria cr
Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();
列表的大小现在是20。如果我在标准中添加一个max results
Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setMaxResults(90);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();
Criteria=getSession().createCriteria(c);
criteria.setResultTransformer(criteria.DISTINCT\u ROOT\u实体);
标准:setMaxResults(90);
标准。添加(限制。等式(“活动”,真实));
List=criteria.List()代码>
。。现在列表的大小是18
我不明白在定义了max results之后,resultset的大小怎么会变小,因为行的数量小于定义的max。这看起来确实像是一个bug,或者hibernate还有一些我不知道的奇怪方面吗
如果您正在寻找此问题的答案,请确保阅读接受的答案及其注释。setMaxResults不适用于外部联接SQL查询。这可能是您的问题:。通过在Hibernate中打开SQL调试并比较生成的查询,可以非常清楚地看到这里发生了什么
使用相当简单的销售
→ <代码>项
一对多映射(希望是自解释的),一个基于条件的查询,如下所示:
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);
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);
Criteria criteria = this.getSession().createCriteria(User.class);
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
criteria.setMaxResults(10);
// First get the results without joining with the other tables
List<User> results = criteria.list();
// at this point the set roles is filled with proxies
// we'll now create and execute the join so these proxies are filled since we're still in the same session
getSession().createCriteria(User.class, "u")
.createAlias("u.roles", "r", CriteriaSpecification.LEFT_JOIN)
.list();
return results;
生成如下SQL:
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);
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);
Criteria criteria = this.getSession().createCriteria(User.class);
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
criteria.setMaxResults(10);
// First get the results without joining with the other tables
List<User> results = criteria.list();
// at this point the set roles is filled with proxies
// we'll now create and execute the join so these proxies are filled since we're still in the same session
getSession().createCriteria(User.class, "u")
.createAlias("u.roles", "r", CriteriaSpecification.LEFT_JOIN)
.list();
return results;
而像这样的查询
:
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);
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);
Criteria criteria = this.getSession().createCriteria(User.class);
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
criteria.setMaxResults(10);
// First get the results without joining with the other tables
List<User> results = criteria.list();
// at this point the set roles is filled with proxies
// we'll now create and execute the join so these proxies are filled since we're still in the same session
getSession().createCriteria(User.class, "u")
.createAlias("u.roles", "r", CriteriaSpecification.LEFT_JOIN)
.list();
return results;
产生类似于:
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
likeDISTINCT\u ROOT\u ENTITY
是一个Java类,它在执行SQL后处理SQL行的结果。因此,当您指定一个maxResults
时,它将作为SQL上的行限制应用;SQL包含到集合
中元素的联接,因此您将SQL结果限制为90个子元素。一旦应用了DISTINCT_ROOT_ENTITY
transformer,可能会导致少于20个根元素,这完全取决于哪个根元素恰好在90个连接的结果中最先出现
HQL中的DISTINCT
的行为非常不同,因为它实际上使用了SQLDISTINCT
关键字,该关键字在行限制之前应用。因此,它的行为与您预期的一样,并解释了2之间的差异
理论上,您应该查看setProjection
以在SQL级别应用投影——类似于c.setProjection(Projections.distinct(Projections.rootEntity())
——但不幸的是Projections.rootEntity()
不存在,我只是编出来的。也许应该 另一种解决方案如下:
运行criteria.list()
而不设置任何别名=>根实体的引用集/列表将填充代理=>在这里您可以正确设置最大结果等
在同一hibernate会话中单独运行别名条件=>上述代理将被初始化
大概是这样的:
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);
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);
Criteria criteria = this.getSession().createCriteria(User.class);
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
criteria.setMaxResults(10);
// First get the results without joining with the other tables
List<User> results = criteria.list();
// at this point the set roles is filled with proxies
// we'll now create and execute the join so these proxies are filled since we're still in the same session
getSession().createCriteria(User.class, "u")
.createAlias("u.roles", "r", CriteriaSpecification.LEFT_JOIN)
.list();
return results;
Criteria=this.getSession().createCriteria(User.class);
标准.setResultTransformer(标准规范.根实体);
标准:setMaxResults(10);
//首先,在不与其他表联接的情况下获取结果
列表结果=标准。列表();
//此时,集合角色中充满了代理
//现在,我们将创建并执行连接,以便填充这些代理,因为我们仍处于同一会话中
getSession().createCriteria(User.class,“u”)
.createAlias(“u.roles”,“r”,CriteriaSpecification.LEFT_JOIN)
.list();
返回结果;
希望这能有所帮助,
Stijn希望这能有所帮助
public List<Employee> getData(int to, int from) {
Criteria hCriteria = null;
List<Employee> viewDataList = null;
List<Employee> exactDataList = null;
try {
hSession = HibernateSessionFactory.getSession();
hTransaction = hSession.beginTransaction();
hCriteria = hSession.createCriteria(Employee.class);
/*
hCriteria.setFirstResult(to);
hCriteria.setFirstResult(from);
*/
hCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
viewDataList = hCriteria.list();
// for limit
exactDataList=viewDataList.subList(from,to);
hTransaction.commit();
} catch (Exception e) {
hTransaction.rollback();
} finally {
try {
hSession.flush();
HibernateSessionFactory.closeSession();
} catch (Exception hExp) {
}
}
return exactDataList;
}
public List getData(int-to,int-from){
标准hCriteria=null;
List viewDataList=null;
List exactDataList=null;
试一试{
hSession=HibernateSessionFactory.getSession();
hTransaction=hsSession.beginTransaction();
hCriteria=hSession.createCriteria(Employee.class);
/*
hCriteria.setFirstResult(to);
hCriteria.setFirstResult(来自);
*/
hCriteria.setResultTransformer(Criteria.DISTINCT\u ROOT\u实体);
viewDataList=hCriteria.list();
//限制
exactDataList=viewDataList.subList(从、到);
hTransaction.commit();
}捕获(例外e){
hTransaction.rollback();
}最后{
试一试{
hSession.flush();
HibernateSessionFactory.closeSession();
}捕获(异常hExp){
}
}
返回数据列表;
}
这是hibernate中的一个已知问题。查看@Cowan以获取生成的SQL和问题的解释。在他们的jira中有一个公开的bug请求。让我们希望有人来修理它:)
您能添加hibernate映射和执行的SQL查询吗?Thomas,不幸的是,不能添加,因为它是一个非常复杂和深入的数据结构——即使是对于相关的POJO也是如此。我将尝试将问题隔离到一个较小的测试用例中,但您的响应可能是我问题的关键。是的,但我想知道的是,为什么它能与纯HQL查询一起工作(我们转而使用Criteria API)。我不太喜欢说明它可能与Hibernate的未来版本一起工作的文档,但是没有提到该文档是何时更新的,所以我不知道该案例是否仍然有效,因为它与HQL一起工作。据我所知,这个问题尚未解决。问得好。正是我需要的!是否有任何已知的(有效的)解决此问题的方法?这显然使我们无法使用标准API:(据我所知,这不是一个好方法。如果你没有处理大量的原始数据,你总是可以选择它们,使用DISTINCT\u ROOT\u ENTITY
,然后获取重新解析列表的前n项。不,不可伸缩,是的,很恶心。不幸的是,没有更好的建议——除非其他人知道在其他情况下,CriteriaAPI可能不适用于这种特殊情况