java - JPA Criteria Builder sum 查询与返回列表的另一个查询相同,不会生成任何 sql,仅返回 0

标签 java mysql hibernate jpa criteria-api

我有两种方法,一种尝试使用 CriteriaBuilder 的 sum 方法对实体上的 numMinutes 字段求和,另一种返回实体列表,我手动循环遍历它们并对 numMinutes 字段求和。

第一个方法返回 0,但第二个方法返回正确答案。诊断此问题时,我在 persistence.xml 中打开了 SQL 打印,第一种方法不打印任何内容。调试时,HQL 与您期望的非常相同。

下面有两个方法,我的问题是,为什么第一个方法这么糟糕,我该怎么做?

尝试对数据库层上的值求和的错误方法:

public int getTotalTimeRecordedForContract(SupplierServiceContract contract) {
    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
    CriteriaQuery<Integer> criteria = builder.createQuery(Integer.class);
    Root<TimeUserTransaction> root = criteria.from(TimeUserTransaction.class);

    List<Predicate> allPredicates = new ArrayList<Predicate>();
    allPredicates.add(
        builder.between(root.get(TimeUserTransaction_.dateRecorded), contract.getStartDate(), contract.getExpiryDate())
    );
    allPredicates.add(
        builder.equal(root.get(TimeUserTransaction_.transaction).get(TransactionPlus_.supplierService), contract.getSupplierService())
    );

    TypedQuery<Integer> query = this.getEntityManager().createQuery(
        criteria.select(builder.sum(root.get(TimeUserTransaction_.numMinutes))).where(allPredicates.toArray(new Predicate[allPredicates.size()]))
    );

    return query.getFirstResult();
}

返回列表的方法应该是相同的,只是它返回所有实体,而不尝试聚合和求和 numMinutes 列:

public List<TimeUserTransaction> getTimeRecordedForContract(SupplierServiceContract contract) {
    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
    CriteriaQuery<TimeUserTransaction> criteria = builder.createQuery(TimeUserTransaction.class);
    Root<TimeUserTransaction> root = criteria.from(TimeUserTransaction.class);

    List<Predicate> allPredicates = new ArrayList<Predicate>();
    allPredicates.add(
        builder.between(root.get(TimeUserTransaction_.dateRecorded), contract.getStartDate(), contract.getExpiryDate())
    );
    allPredicates.add(
        builder.equal(root.get(TimeUserTransaction_.transaction).get(TransactionPlus_.supplierService), contract.getSupplierService())
    );

    TypedQuery<TimeUserTransaction> query = this.getEntityManager().createQuery(
        criteria.select(root).where(allPredicates.toArray(new Predicate[allPredicates.size()]))
    );

    return query.getResultList();
}

在调试时,JPQL 似乎适用于第一种方法:

select sum(generatedAlias0.numMinutes) from TimeUserTransaction as generatedAlias0 where ( generatedAlias0.dateRecorded between :param0 and :param1 ) and ( generatedAlias0.transaction.supplierService=:param2 )

第二个:

select generatedAlias0 from TimeUserTransaction as generatedAlias0 where ( generatedAlias0.dateRecorded between :param0 and :param1 ) and ( generatedAlias0.transaction.supplierService=:param2 )

这更让我困惑,好像第一个方法生成 HQL,为什么它不将其转换为 JPQL 并在数据库上运行。

我正在使用连接到 mysql 数据库的 JPA 的 hibernate 实现 - 以防万一这是相关的。

最佳答案

您不需要.groupBy(root.get(TimeUserTransaction_.numMinutes))。如果您选择多列并将一列与计数、总和等聚合函数一起使用,则需要 GROUP BY。由于您只选择 numMinutes 的总和,因此您不需要这样做。

当您这样做时,它会将所有唯一的 numMinutes 及其总和分组。如果 numMinutes 为 0,那么它们也将被加起来为 0 并被分组在一起。 0 将位于顶部,因为默认情况下它将按升序排序,并且 query.getFirstResult(); 将返回 0。

public int getTotalTimeRecordedForContract(SupplierServiceContract contract) {
    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
    CriteriaQuery<Integer> criteria = builder.createQuery(Integer.class);
    Root<TimeUserTransaction> root = criteria.from(TimeUserTransaction.class);

    List<Predicate> allPredicates = new ArrayList<Predicate>();
    allPredicates.add(
        builder.between(root.get(TimeUserTransaction_.dateRecorded), contract.getStartDate(), contract.getExpiryDate())
    );
    allPredicates.add(
        builder.equal(root.get(TimeUserTransaction_.transaction).get(TransactionPlus_.supplierService), contract.getSupplierService())
    );

    TypedQuery<Integer> query = this.getEntityManager().createQuery(
        criteria.select(builder.sum(root.get(TimeUserTransaction_.numMinutes))).where(allPredicates.toArray(new Predicate[allPredicates.size()]));
    );

    return query.getFirstResult();
}

关于java - JPA Criteria Builder sum 查询与返回列表的另一个查询相同,不会生成任何 sql,仅返回 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34588788/

相关文章:

mysql - 获取客户 MySQL 的最近两个日期

java - 获取 hibernate 中实体的最后一个ID

java - 父子关系-自连接映射

java - 如何使用实体限制实体数量?

java - 将JSP中的参数传递给Servlet

Java泛型语法

java - JBoss 7 内存配置为 4G 内存,64 位

java - 以下sql代码无法插入数据是什么原因?

mysql - MariaDB 崩溃 : Table doesn't exist in engine && can't recover tables

mysql - 如何将 Tomcat 配置为不使用数据库连接池