【问题标题】:Referring to an earlier aliased field in a criteria query在条件查询中引用较早的别名字段
【发布时间】:2010-12-29 13:54:17
【问题描述】:

在这个查询中:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> q = cb.createTupleQuery();

// FROM GamePlayedEvent gpe
Root<GamePlayedEvent> gpe = q.from(GamePlayedEvent.class);
// SELECT gameId, COUNT(*) AS count, AVG(duration)
// AS avDur, AVG(rewardCurrency) AS avCur, AVG(rewardXP) avXp
q.select(cb.tuple(
    gpe.<String>get("gameId"),
    cb.count(gpe).alias("count"),
    cb.avg(gpe.<Double>get("duration")).alias("avDur"),
    cb.avg(gpe.<Integer>get("rewardCurrency")).alias("avCur"),
    cb.avg(gpe.<Integer>get("rewardXp")).alias("avXp")
));
// WHERE loginTime BETWEEN ...
q.where(cb.between(gpe.<Date>get("time"), fromTime, toTime));
// GROUP BY gameId
q.groupBy(gpe.<String>get("gameId"));
// ORDER BY count DESC
q.orderBy(cb.desc(???));

如何添加ORDER BY count DESC,指的是SELECT子句中定义的“计数”?

【问题讨论】:

    标签: java hibernate jpa criteria jpa-2.0


    【解决方案1】:

    如果你只是捕获了 count 表达式,然后直接使用它呢?

    Expression event_count = cb.count(gpe);
    
    q.select(cb.tuple( 
      gpe.<String>get("gameId"), 
      event_count,
      ... 
    )); 
    
    q.orderBy(cb.desc(event_count));
    

    【讨论】:

    • 如果您需要引用列但需要特定名称怎么办?不只是重新评估不同查询部分中的表达式
    【解决方案2】:

    我今天遇到了同样的问题,但没有一个建议的解决方案对我有用,因为我不仅需要在 order by 子句中重用表达式,还需要在 group by 子句中重用表达式。 一个明显的解决方案是在数据库级别创建一个视图,但这有点笨拙,会创建不必要的子查询,如果 db 用户没有被授予足够的权限,甚至是不可能的。我最终实现的一个更好的选择是写这样的东西

    q.select(cb.tuple( 
      gpe.<String>get("gameId"), 
      cb.count(gpe),
      ... 
    )).groupBy(cb.literal(2)).orderBy(cb.literal(2));
    

    这种方法的第一个缺点是代码容易出错。另一个缺点是生成的 sql 查询包含序数位置表示法,它适用于某些数据库(如 postgresql 或 mariadb)但不适用于其他数据库(如 sql server)。然而,就我而言,我发现这是最好的选择。

    在 jpa 2.1 上测试,hibernate 5.2.3 作为提供者,postgresql 9.6。

    【讨论】:

    • 谢谢,它救了我。由于某种原因,Hibernate 不喜欢按选择列表中已有的子查询进行分组。
    【解决方案3】:

    尽管 Pro JPA 2 书描述了 alias 方法可用于生成 sql 查询别名(第 251 页),但我没有成功使其与 EclipseLink 或 Hibernate 一起工作。对于您的问题,我会说您的 orderBy 行应为:

    q.orderBy(cb.desc(cb.count(gpe));
    

    如果它被不同的供应商支持。

    就我的研究而言,别名方法仅用于命名选择中使用的 tuble 中的元素(因此仅用于投影)。

    我有一个问题。您为什么要为此查询使用 JPA Criteria API。它(查询)本质上是静态的,所以为什么不使用可以直接定义查询别名的 JPQL。

    【讨论】:

      【解决方案4】:

      您是否尝试过使用别名设置投影?

      criteria.setProjection(Projections.projectionList()
         .add(Projections.count("item.id"), "countItems"));
      criteria.addOrder(Order.desc("countItems"));
      

      【讨论】:

      • 这就是 Hibernate Criteria API。这个问题是关于 JPA 2 Criteria API(它是 Hibernate 实现)。令人困惑的是,这些不是一回事。
      【解决方案5】:

      对于总和聚合字段,我有以下代码对我有用:

      CriteriaBuilder cb = em.getCriteriaBuilder();
      CriteriaQuery<T> cq = cb.createQuery(entity);
      Root<T> root = cq.from(entity);
      
      cq.orderBy(cb.desc(cb.sum(root.get(orderByString))));
      
      // orderByString is string entity field that is being aggregated and which we want to put in orderby clause as well. 
      

      【讨论】:

        猜你喜欢
        • 2011-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-09
        • 1970-01-01
        • 1970-01-01
        • 2013-05-30
        相关资源
        最近更新 更多