java JPA/Hibernate 返回 BigDecimal 不长
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15345440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPA/Hibernate returning BigDecimal not Long
提问by jeff
I'm computing a SUM grouped by months
我正在计算按月分组的 SUM
Query q = entityManager.createNativeQuery(qlString);
q.setParameter("program", program);
@SuppressWarnings("unchecked")
List<Long> resultList = (List<Long>) q.getResultList();
long tend = System.currentTimeMillis();
When I pass in two resultsLists (closed:ResultsList of Closed items, closedLate: ResultsList of items Closed late) into a method that computes percentages, I get
当我将两个结果列表(已关闭:已关闭项目的结果列表,已关闭:已关闭项目的结果列表)传递到计算百分比的方法中时,我得到
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;
}
}
In Eclipse debug mode closed is showing as BigDecimal. Why is this when I decalre
在 Eclipse 调试模式下关闭显示为 BigDecimal。为什么我贴标时会这样
List<Long> resultList = (List<Long>) q.getResultList();
List<Long> resultList = (List<Long>) q.getResultList();
EDIT-Hibernate Query:
编辑休眠查询:
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;
}
EDIT 2
编辑 2
I think I am stuck with a BigDecimal? http://weblogs.java.net/blog/mb124283/archive/2007/04/java_persistenc.html
我想我被 BigDecimal 困住了? http://weblogs.java.net/blog/mb124283/archive/2007/04/java_persistenc.html
回答by Jon Skeet
You should already be getting a warning showing that your cast isn't really checking things fully. Type erasuremeans that at execution time, there's no difference between a List<Long>
and a List<BigDecimal>
. So the cast succeeds, and it's only the later implicitcast to Long
which fails.
您应该已经收到警告,表明您的演员并没有真正全面检查事情。类型擦除意味着在执行时, aList<Long>
和 a之间没有区别List<BigDecimal>
。所以演员表成功了,只有后来的隐式演员表Long
失败了。
Basically you need to change your query to make sure it creates Long
values instead.
基本上,您需要更改查询以确保它创建Long
值。
回答by LaurentM
I just faced the same problem.
我刚刚面临同样的问题。
One solution is to add scalar (https://stackoverflow.com/a/29479658).
一种解决方案是添加标量 ( https://stackoverflow.com/a/29479658)。
But in my case (Spring data jpa with @Query annotation), I couldn't add it.
One workaround is to get result list as a List <? extends Number>
(superclass of Long and BigInteger)
但在我的情况下(带有@Query 注释的 Spring 数据 jpa),我无法添加它。一种解决方法是将结果列表作为List <? extends Number>
(Long 和 BigInteger 的超类)获取
Then you can call the Number's method longValue()
.
然后你可以调用 Number 的方法longValue()
。
In java 8, your sample could become:
在 Java 8 中,您的示例可能会变成:
List<? extends Number> resultListAsNumber = q.getResultList();
List<Long> resultList = resultListAsNumber.stream().map(i -> i.longValue()).collect(Collectors.toList());
This solution avoids String convertion and will work if one day hibernate returns Long.
此解决方案避免了字符串转换,如果有一天休眠返回 Long,该解决方案将起作用。
回答by Sabyasachi Mukherjee
You should iterate over the results and convert the objects from String:
您应该遍历结果并从 String 转换对象:
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();
}