问题 Hibernate Criteria:不同的实体然后限制


我有一个标准,返回应用程序所需的所有数据,基本上:

Criteria criteria = session.createCriteria(Client.class);
criteria.createAlias("address", "address");
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();

问题是关系客户端/地址是双向的:客户端上有一个地址,一个地址可能属于多个客户端。

我想根据他们的pk检索“单个”客户端对象,当一些客户端显示在表中时。

因为首先执行setFirstResult / setMaxResults,所以我在已经应用的限制内获得了重复的客户端。之后(使用的应用程序级别不是group by)hibernate获取重复客户端的rids,因此我最终得到了setMaxResults中指定的最大值的客户端。

无法分组(投影组),因为它不会返回客户端/地址中所需的所有列,只会返回查询所分组的组。

(总而言之,我的表每页有100个结果,但在丢弃重复项后我有98个结果而不是100个...)这是因为限制:LIMIT 0,100应用于休眠组之前应该执行的AFTER)


11403
2017-08-16 14:54


起源



答案:


正如在“Ashish Thukral”链接的帖子中指出的那样,下一行解决了这个问题:

criteria.setFetchMode("address.clients", FetchMode.SELECT);

它可以防止导致问题的连接。

当然,可以从xml配置文件中删除fetch =“join”,但此解决方案不会影响可能正在检索bean的其他位置。


9
2017-09-18 15:14



FetchMode.SELECT为我修复了它 - 在这种情况下其他模式不起作用。 - Morten Holmgaard
FetchMode.SELECT很棒......除了因为某些原因它强制提取。看到 docs.jboss.org/hibernate/core/3.3/api/org/hibernate/...  有没有办法告诉hibernate只是在被提取的实体的pk上做一个“不同的”?这似乎是最明显的琐碎事情,而且,按照惯例,hibernate使我们的生活变得极为复杂。 - Marc
顺便说一句,使用HQL执行此操作与听起来一样简单。您只需在查询中添加“distinct”一词即可。为什么使用Criteria API这是如此痛苦,这是我无法想象的。我们都可以开始使用OO数据库吗? - Marc


答案:


正如在“Ashish Thukral”链接的帖子中指出的那样,下一行解决了这个问题:

criteria.setFetchMode("address.clients", FetchMode.SELECT);

它可以防止导致问题的连接。

当然,可以从xml配置文件中删除fetch =“join”,但此解决方案不会影响可能正在检索bean的其他位置。


9
2017-09-18 15:14



FetchMode.SELECT为我修复了它 - 在这种情况下其他模式不起作用。 - Morten Holmgaard
FetchMode.SELECT很棒......除了因为某些原因它强制提取。看到 docs.jboss.org/hibernate/core/3.3/api/org/hibernate/...  有没有办法告诉hibernate只是在被提取的实体的pk上做一个“不同的”?这似乎是最明显的琐碎事情,而且,按照惯例,hibernate使我们的生活变得极为复杂。 - Marc
顺便说一句,使用HQL执行此操作与听起来一样简单。您只需在查询中添加“distinct”一词即可。为什么使用Criteria API这是如此痛苦,这是我无法想象的。我们都可以开始使用OO数据库吗? - Marc


如果您根据ID查找客户端,如下所示。根据您的标准,不需要max和init大小,因为它总是返回一个客户端。

Criteria criteria = getSession().createCriteria(Client.class);
criteria .add(Restrictions.eq("id", yourClientId);
criteria.createAlias("address", "address");
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();

如果您根据ID查找地址,如下所示。

Criteria criteria = getSession().createCriteria(Client.class);
criteria.createAlias("address", "address");
criteria .add(Restrictions.eq("address.id", yourAddressId);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();

6
2017-08-16 15:18



非常感谢您的回答,但我一直在寻找所有客户,并将其作为回复页面返回。问题不是一个应该返回100个结果的页面,在对它们进行分组后返回的更少(DISTINCT_ROOT_ENTITY)。该分组应该在限制之前发生...... - kandan
第二个块可能导致@kandan在他的问题中发布的行数较少 - Ashish Thukral


如果我正确理解您的关系,您将在每个客户端实体类的地址和一个地址中有一个客户列表。 所以,如果你只想要一个客户列表,那么最重要的是,你不能只是得到它们

Criteria criteria = session.createCriteria(Client.class);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();

为什么要创建别名并使用distinct_root_entity?如果您需要获取该地址,当您在DAO或ServiceImpl中访问它时,Hibernate会为您懒散地获取它。

如果我错了,请纠正我。


0
2017-08-17 03:32



谢谢。我正在创建一个别名来强制hibernate在查询中获取其他数据,因为我可能通过例如他们的邮政编码过滤客户端(是带有过滤器的分页表)。所以我得到了我需要的所有数据:有地址的客户。问题是,地址也有一组具有该地址的客户端,我需要一个resulttransformer来通过他们的id来统一客户端。可能在不修改任何注释的情况下,可以告诉hibernate不要检索/加入类/表的特定列,而是对其他字段执行此操作,无论是否指定了默认定义(lazy或not)。 - kandan
我想你正在寻找这个 stackoverflow.com/questions/5567754/... - Ashish Thukral
是的,谢谢你。 - kandan