【问题标题】:Is there a better way than using DetachedCriteria for pagination?有没有比使用 DetachedCriteria 进行分页更好的方法?
【发布时间】:2016-02-13 16:41:44
【问题描述】:

使用 Hibernate 的 Criteria api 进行排序和分页有一个很大的限制,它需要从数据库中检索不同的结果。像 DistinctRootTransformer 这样的 api 提供的工具将不起作用,因为它是在 从 db 检索实体之后应用的,因此会中断分页和排序。获得具有关联限制的查询的不同结果的唯一方法是通过 DetachedCriteria 限制结果集:

DetachedCriteria dc = DetachedCriteria.forClass(Household.class, "h")
                .createAlias("cats", "c", JoinType.LEFT_OUTER_JOIN)
                .add(Restrictions.or(
                        Restrictions.isEmpty("cats"),
                        Restrictions.ne("c.name", "Sylvester")
                ))
                .setProjection(Projections.distinct(Projections.property("h.id")));

Criteria criteria = session.createCriteria(Household.class)
                .add(Property.forName("id").in(dc));

...apply paging, sorting and filtering to criteria.

有没有人知道更好的方法,例如省略子查询并使用连接而不破坏分页?我的目标是找到一个可重用的解决方案,例如只将一个标准传递给另一个应用分页、排序和过滤的方法。

更新:

以下代码不起作用。由于加入,我必须使用 Resulttransformer,以获得不同的结果。但是,它是在排序和分页之后应用的。

Criteria criteria = session.createCriteria(Household.class)
   .createAlias("cats", "c", JoinType.LEFT_OUTER_JOIN)
   .add(Restrictions.ne("c.name","Sylvester"))
   .setFirstResult((page - 1) * pagesize)
   .setMaxResults(pagesize)
   .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

例如调试 sql 数据库会返回类似的内容:

household_id=1,...cat_ids={1,2};household_id=1,...cat_ids={1,2};household_id=2,...cat_ids={1};

在此示例中,将 pagesize 设置为 1 并查看页面 2 应该返回 uid 2,因为只有两个不同的用户。但正如您在数据库输出中看到的那样,它返回了错误的 uid 1,因为 Resulttransformers 之后会启动。

【问题讨论】:

  • 如何将排序应用于您的标准?为了确保页面之间没有重复,我相信您必须强制执行总排序。可以对分离的条件进行排序,但您将其投影为仅一个 ID,因此您只能按 ID 排序。考虑示例:获取目录中 150 件蓝色衬衫的第 1 页尺寸 50 件蓝色衬衫,按价格升序排序;当用户请求第 2 页时,所有内容都应该是看不见的并且更昂贵,对吧?如何保证? (假设需要连接的衬衫如面料、收藏等存在一对多关系。)

标签: java hibernate sorting hibernate-criteria data-paging


【解决方案1】:

如果您以某种方法创建 DetachedCriteria 然后使用它,您可以尝试使用以下方法将 DetachedCriteria 转换为 Criteria:

DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Your.class);
// then add all your restrictions and convert
Criteria criteria = detachedCriteria.getExecutableCriteria(session);

然后应用你的分页

criteria.setFirstResult(pageable.getPage() * pageable.getSize());
criteria.setMaxResults(pageable.getSize());

然后执行条件。例如:

List<T> result = criteria.list();

【讨论】:

    【解决方案2】:

    当我需要分页时,我从不使用 DetachedCriteria,而是使用普通 Criteria,控制第一和最大结果。

    从视图中我确定我需要显示哪个页面,一旦我准备好标准,我就会这样配置:

    criteria.setMaxResults(lazyQuery.getPageSize());
    criteria.setFirstResult(layQuery.getStart());
    

    lazyQuery是我自己模型的一个对象,用于视图和业务逻辑。这很完美。

    【讨论】:

    • 但是如何确保标准具有独特的结果?如果此条件与另一个实体有任何连接,则分页和排序将被破坏,因为 maxResults、firstResult 和排序应用于数据库级别的冗余数据。如果您将别名应用于主要标准而不是分离的标准,则很容易发生这种情况,我在上面的代码 sn-p 中显示了这一点。
    • 我一直在非常复杂的条件中使用它们,有几个连接,使用别名和排序结果,我从来没有遇到过你描述的问题。
    • 我更新了我的帖子以展示一个案例,其中将 setMaxResults 应用于任意查询是行不通的。要点是:有时您必须使用 DetachedCriterias/子查询或连接。
    • @Journeycorner 现在我刚刚了解您的问题。与DISTINCT_ROOT_ENTITY resultTransformer 有冲突。抱歉,我帮不了你,但我找到了这个 thread criteria.setFetchMode("xxxxxxx", FetchMode.SELECT) 解决了类似的查询
    • 看起来不错,但他们没有对加入的关联应用任何限制。我需要弄清楚 FetchMode.SELECT 是否可以在这里代替真正的加入。
    猜你喜欢
    • 2019-08-13
    • 2017-03-12
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-17
    • 2011-03-09
    相关资源
    最近更新 更多