【问题标题】:JPA Criteria query group by uses only the idJPA Criteria query group by 仅使用 id
【发布时间】:2015-02-27 19:37:15
【问题描述】:

这是一个示例实体:

public class Account{

   @Id
   Long id
   Double remaining;
   @ManyToOne
   AccountType type
}

public class AccountType{
   @Id
   Long id;
   String name;
}  

现在我创建一个条件查询,加入如下:

CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createquery();
Root<Account> accountRoot = criteriaQuery.from(Account.class);
Join<Account, AccountType> typeJoin = accountRoot.join(Account_.type);

criteriaQuery.multiSelect(
    typeJoin,
    criteriaBuilder.sum(accountRoot.get(Account_.remaining))
);

criteriaQuery.groupBy(typeJoin);
Query query = getEntityManager().createQuery(criteriaQuery);
query.getResultList();  

以上代码生成Sql命令如下:

select accType.id, accType.name, sum(acc.remaining)
from account acc join accType on acc.accounttype_id = accType.id
group by accType.id  

以上代码在 PosgreSQL 中工作,但不能在 Oracle 中运行,因为在其中选择了未出现在 group by 子句中的 accType.name。

更新
我想我的问题对你来说不是很清楚。我的问题与group by 中的 PostgreSQL 或 Oracle 行为无关。我的问题是:
我在group by 子句中使用typeJoin(这意味着我希望休眠使用group by 中的所有AccountType 字段),但是为什么休眠只在group by 上使用身份字段?如果我只使用group by 中的标识字段,那么我可以使用以下语句:

criteriaQuery.groupBy(typeJoin.get(AccountType_.id)) ;

【问题讨论】:

    标签: java hibernate jpa group-by criteriaquery


    【解决方案1】:

    JPA/Hibernate 不会自动在 group by 子句中包含所有实体属性,因此您必须手动指定它们:

    CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
    Root<Account> accountRoot = criteriaQuery.from(Account.class);
    Join<Account, AccountType> typeJoin = accountRoot.join(Account_.type);
    
    criteriaQuery.multiSelect(
        typeJoin.get("id"),
        typeJoin.get("name"),
        criteriaBuilder.sum(accountRoot.get(Account_.remaining))
    );
    
    criteriaQuery.groupBy(typeJoin.get("id"), typeJoin.get("name"));
    Query query = getEntityManager().createQuery(criteriaQuery);
    query.getResultList();  
    

    【讨论】:

    • 这不是个好主意。在此解决方案中,任何时候 AccountType 更改我都会更改我的所有查询。当然我可以通过反思来处理它,但我认为必须有更好的解决方案。你确定hibernate不能包含所有实体属性吗?
    • 您可以简单地指定accountType.id,然后使用二级缓存来加载它。
    • 您当然也可以使用 JPA 元模型来检索实体类型的所有属性并将它们放入通用的组中。
    • @VladMihalcea 还是这样吗?我正面临这个问题,不知道现在是否有解决方法?
    • 很可能情况仍然如此,因为这不是一个真正的问题。如果有人想通过QueryHint 添加改进,那么查询可以对所有列进行分组。
    【解决方案2】:

    如果使用 GROUP BY,Oracle 要求选择列表中的每一列都在 GROUP BY 中。
    PostgreSQL 是一样的,除了按主键分组时,它允许您选择任何列。

    来自Oracle docs

    在包含 GROUP BY 子句的查询中,选择的元素 list 可以是聚合函数、GROUP BY 表达式、常量或 涉及其中之一的表达式。

    来自PostgreSQL docs

    当存在 GROUP BY 或任何聚合函数时,它 SELECT 列表表达式引用未分组时无效 聚合函数内或未分组列除外的列 在功能上取决于分组列,因为会有 否则为一个未分组的返回多个可能的值 柱子。如果分组列(或 子集)是包含 未分组的列。

    【讨论】:

      猜你喜欢
      • 2020-02-22
      • 2017-07-17
      • 1970-01-01
      • 2015-07-25
      • 1970-01-01
      • 2014-09-02
      • 1970-01-01
      • 2012-09-07
      • 1970-01-01
      相关资源
      最近更新 更多