HQL - StandardAnsiSqlAggregationFunctions$SumFunction.determineJdbcTypeCode

HQL - StandardAnsiSqlAggregationFunctions$SumFunction.determineJdbcTypeCode

我想创建 TotalDTO 的新对象列表。 TotalDTO 的字段是 OrderDTO.total 在各种条件下的总和和计数。 OrderDTO 映射到数据库,而 TotalDTO 不是。 我正在使用 EntityManager:

@PersistenceContext
private EntityManager entityManager;

public List<TotalDTO> listOfTotal(LocalDate from, LocalDate to)
{   
    String hql = "SELECT new com.CompanyName.DTO.TotalDTO(o.date, COALESCE(SUM(IF(o.platform = 'China', o.total, 0)), 0),"
            + " COALESCE(SUM(IF(o.platform != 'China', o.total, 0)), 0),"
            + " COUNT(o.orderId),"
            + " COALESCE(SUM(IF(o.platform = 'coupons', o.total, 0)), 0),"
            + " COALESCE(SUM(o.total), 0))"
            + " FROM OrderDTO o WHERE (o.date BETWEEN :from AND :to) GROUP BY o.date ORDER BY o.date";
    
    Query query = entityManager.createQuery(hql);
    
    query.setParameter("from", from);
    query.setParameter("to", to);

    List<TotalDTO> listOfTotal = (List<TotalDTO>)query.getResultList();
    
    return listOfTotal;

我的 TotalDTO 构造函数:

public TotalDTO(LocalDate date, BigDecimal china, BigDecimal spent, long totalOrders, BigDecimal totalCoupons,
        BigDecimal totalSum)
{
    this.date = date;
    this.china = china;
    this.spent = spent;
    this.totalOrders = totalOrders;
    this.totalPoints = totalCoupons;
    this.total = totalSum;
}

我收到此错误:

java.lang.NullPointerException: null
    at org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions$SumFunction.determineJdbcTypeCode(StandardAnsiSqlAggregationFunctions.java:200) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions$SumFunction.getReturnType(StandardAnsiSqlAggregationFunctions.java:158) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.findFunctionReturnType(SessionFactoryHelper.java:430) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.hql.internal.ast.tree.AggregateNode.getDataType(AggregateNode.java:68) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
...

此查询在 SQL 中有效,但在 Hibernate 中无效。

我读过这个:New Object with HQL - NPE on StandardAnsiSqlAggregationFunctions, determineJdbcTypeCode 但是如果我理解正确的话,post 中的人会有不同的问题。但它与我的有关。

更新: 此方法中 class org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions 中抛出异常:

protected final int determineJdbcTypeCode(Type type, Mapping mapping) throws QueryException 
{
    try
    {
        final int[] jdbcTypeCodes = type.sqlTypes(mapping);
        if ( jdbcTypeCodes.length != 1 )
        {
            throw new QueryException("multiple-column type in sum()");
        }
        return jdbcTypeCodes[0];
    }
    catch ( MappingException me )
    {
        throw new QueryException(me);
    }
}

这里的Type类型为null,我估计是不行的。

更新2: 我也试过投

String hql = "SELECT new com.CompanyName.DTO.TotalDTO(o.date, CAST( COALESCE(SUM(IF(o.platform = 'China', o.total, 0)), 0) AS decimal ),"
        + " CAST(COALESCE(SUM(IF(o.platform != 'China', o.total, 0)), 0) AS decimal ),"
        + " CAST(COUNT(o.orderId) AS long),"
        + " CAST (COALESCE(SUM(IF(o.platform = 'coupons', o.total, 0)), 0) AS decimal ),"
        + " CAST(COALESCE(SUM(o.total), 0) AS decimal) )"
        + " FROM OrderDTO o WHERE (o.date BETWEEN :from AND :to) GROUP BY o.date ORDER BY o.date";

我对此进行了进一步测试,我注意到仅当我使用 IF 语句时才会发生异常,但我需要 IF 语句。如果在 SQL 中工作,HQL 的工作方式是否不同?

看来问题不在于构造函数。每当我使用 IF 语句时,都会出现此错误。当我在 MySQL 中使用 IF 时,它起作用了,但在这里不起作用。所以我改成 CASE:

        String hql = "SELECT new com.CompanyName.DTO.TotalDTO(o.date,"
                + " COALESCE(SUM(CASE WHEN o.platform = 'China' THEN o.total ELSE 0 END), 0), "
                + " COALESCE(SUM(CASE WHEN o.platform != 'China' THEN o.total ELSE 0 END), 0), "
                + " COUNT(o.orderId), "
                + " COALESCE(SUM(CASE WHEN o.platform = 'coupons' THEN o.total ELSE 0 END), 0),"
                + " COALESCE(SUM(o.total), 0)) "
+ " FROM OrderDTO o WHERE (o.date BETWEEN :from AND :to) GROUP BY o.date ORDER BY o.date";