JPA/Hibernate返回BigDecimal而不是Long

12

我正在按月份分组计算总和

Query q = entityManager.createNativeQuery(qlString);
q.setParameter("program", program);
@SuppressWarnings("unchecked")
List<Long> resultList = (List<Long>) q.getResultList();
long tend = System.currentTimeMillis();

当我将两个结果列表 (closed: 已关闭项目的结果列表, closedLate: 已过期关闭项目的结果列表) 传入一个计算百分比的方法时,我得到了

 javax.servlet.ServletException: java.lang.ClassCastException: java.math.BigDecimal cannot be cast to java.lang.Long

.

private List<Long> computeOTR(List<Long> closed, List<Long> closedLate) {
    List<Long> monthlyOTR = new ArrayList<Long>();
    long numerator;
    Long denominator;
    for (int i = 0; i <11; i++) {
        numerator = closed.get(i) - closedLate.get(i); <----java.lang.ClassCastException
        denominator = closed.get(i);
        long percentage = (int)(numerator * 100.0 / denominator + 0.5);
        monthlyOTR.add(i, percentage);
    }
    return monthlyOTR;

}

在Eclipse调试模式下,closed被显示为BigDecimal类型。当我声明

List<Long> resultList = (List<Long>) q.getResultList();

编辑-Hibernate查询:

public List<Long> findClosedLateByProgram(String program) {

    long tstart = System.currentTimeMillis();
    //@formatter:off
    String qlString = "with PRJ as ( " +
            "select  trunc(END_DATE) as END_DATE,  " +
            "trunc(NEED_DATE) as NEED_DATE   " +
            "from (SELECT UNIQUE * FROM TEST where PROGRAM_NAME = :program " +
            "AND ACTION_BY_ORG = 'AAA') " +
            "),  " +
            "DATES as ( select add_months(trunc(last_day(SYSDATE)), level-7) as thedate  " +
            "from dual connect by level <= 12  )   " +
            "SELECT nvl(sum(case when NEED_DATE <  trunc(thedate,'mm') AND END_DATE between trunc(thedate,'mm') and thedate then 1 end), 0 ) as CLOSED_LATE  " +
            "FROM  DATES, PRJ  " +
            "GROUP BY thedate ORDER BY thedate";
    //@formatter:on

    Query q = entityManager.createNativeQuery(qlString);
    q.setParameter("program", program);
    // q.setParameter("today",date, TemporalType.DATE);

    @SuppressWarnings("unchecked")
    List<Long> resultList =  q.getResultList();
    long tend = System.currentTimeMillis();
    long elapsed = tend-tstart;
    System.out.println("Elapsed Time For Closed But Late: " + elapsed);
    return resultList;
}

编辑2

我认为我被一个BigDecimal卡住了? http://weblogs.java.net/blog/mb124283/archive/2007/04/java_persistenc.html


请参见https://dev59.com/K3A65IYBdhLWcg3w5zDB。 - Vadzim
3个回答

4

我刚遇到了同样的问题。

一种解决方法是添加scalar (https://dev59.com/D2Ml5IYBdhLWcg3wBzDy#29479658)。

但在我的情况下(使用Spring data jpa和@Query注释),我无法添加它。 一种解决方法是将结果列表作为 List <? extends Number>(Long和BigInteger的超类)获取

然后你可以调用Number的方法longValue()

在Java 8中,你的示例可能变成:

List<? extends Number> resultListAsNumber =  q.getResultList();
List<Long> resultList = resultListAsNumber.stream().map(i -> i.longValue()).collect(Collectors.toList());

这个解决方案避免了字符串转换,如果有一天 hibernate 返回 Long 类型也能正常工作。

4
您应该已经收到了一个警告,显示您的转换并没有完全检查事情。类型擦除意味着在执行时,List<Long>List<BigDecimal>之间没有区别。因此,转换成功了,只有后来的隐式转换到Long失败了。
基本上,您需要更改查询以确保它创建Long值。

我明白了。我的查询结果列表是[33,23,25,29,15,30, NULL, NULL, NULL, NULL, NULL, NULL]。我猜测NULL将其转换为BigDecimal。 - jeff
@jeff:不,这将取决于您的查询本身。听起来它似乎认为它正在获取整数数据。 - Jon Skeet
你说得没错。我刚刚修复了我的查询,使其返回0而不是NULL,但列表仍然是BigDecimal类型。查询只是计算记录数,所以只有整数数据。如果我从JPA查询中删除所有泛型,然后在调试模式下检查resultsList,它会显示我的12个整数值的BigDecimal类型。我不明白还有什么其他方法可以修改查询。 - jeff
@jeff:我们看不到你的查询,这让帮助你变得非常困难。 - Jon Skeet
@jeff:嗯,我不清楚你为什么要使用NVL——我猜你可以只使用:SELECT sum(case when NEED_DATE < trunc(thedate,'mm') AND END_DATE between trunc(thedate,'mm') and thedate then 1 else 0 end) - Jon Skeet
最初我没有使用NVL。这产生了[33,23,25,29,15,30,NULL,NULL,NULL,NULL,NULL,NULL](我的第一条评论)。使用NVL后,它变成了[33,23,25,29,15,30,0,0,0,0,0,0]。 - jeff

0
你应该遍历结果并将对象从字符串转换:
    Query query = createSQLQuery(sql);
    List<Long> ids = new java.util.ArrayList<Long>();
    java.util.Iterator res = query.list().iterator();

    try {
        while(res.hasNext()){
            ids.add(new Long(res.next().toString()));
        }
    } catch(Exception ex) {
        ex.printStackTrace();
    }

BigDecimal#longValue() - MirandaVeracruzDeLaHoyaCardina

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接