【问题标题】:Hibernate Criteria: distinct entities and then limitHibernate Criteria:区分实体然后限制
【发布时间】:2013-08-19 00:46:21
【问题描述】:

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

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,所以我在已应用的限制内获得了重复的客户端。之后(未使用分组依据的应用程序级别)休眠消除了重复的客户端,因此我最终得到的客户端少于 setMaxResults 中指定的最大值。

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

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

【问题讨论】:

    标签: java hibernate group-by criteria


    【解决方案1】:

    如果您根据 id 查找 Client 如下。根据您的标准,不需要最大和初始大小,因为它总是返回一个客户端。

    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();
    

    【讨论】:

    • 非常感谢您的回答,但我正在寻找所有客户,并在页面中将它们作为响应返回。问题在于应该返回 100 个结果的页面,在对它们进行分组后返回更少(DISTINCT_ROOT_ENTITY)。该分组应该在限制之前发生......
    • 第二个区块可能会导致@kandan 在他的问题中发布的行数减少
    【解决方案2】:

    如果我正确理解您的关系,您将在地址中拥有一个客户列表,在每个客户实体类中都有一个地址。 所以如果你只是想要一个客户列表,有什么大不了的,你不能直接得到他们吗

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

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

    如果我错了,请纠正我。

    【讨论】:

    • 谢谢。我正在创建一个别名以强制休眠获取查询中的其他数据,因为我可能正在过滤客户端,例如他们的邮政编码(是一个带有过滤器的分页表)。所以我得到了我需要的所有数据:有地址的客户。问题是,随着地址还有一组具有该地址的客户,我需要一个结果转换器来通过他们的 id 来统一客户。可能有可能,在不修改任何注释的情况下,告诉 hibernate 不要检索/加入类/表的特定列,而是对其他字段执行此操作,无论指定了默认定义(惰性或非惰性)。
    • 我想你正在寻找这个stackoverflow.com/questions/5567754/…
    【解决方案3】:

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

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

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

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

    【讨论】:

    • FetchMode.SELECT 为我修复了它 - 在这种情况下其他模式不起作用。
    • FetchMode.SELECT 很棒...除了它出于某种原因强制进行急切的提取。见docs.jboss.org/hibernate/core/3.3/api/org/hibernate/…有没有办法告诉hibernate简单地对被获取的实体的pk做一个“不同的”?这似乎是最明显的一件微不足道的事情,而且像往常一样,hibernate 让我们的生活变得极其复杂。
    • 顺便说一句,使用 HQL 执行此操作就像听起来一样简单。您只需在查询中添加单词“distinct”。为什么使用 Criteria API 会如此繁琐,这超出了我的理解。我们都可以开始使用 OO 数据库了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 2011-05-21
    • 1970-01-01
    • 2017-09-29
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    相关资源
    最近更新 更多