开发者

Hibernate error from Projections.sum when sum too large for field's type

I am trying to use a Projection to sum up a size field when grouped by a role. The Criteria is working fine except for when the sum no longer fits into the type of the size field. The database I am using MySQL returned a larger type for the sum when I ran the generated query directly against the database but I get an exception from Hibernate. The size field is a long in Java and a BIGINT in MySQL. Is there anyway to get Hibernate to return the larger type, it seems to be trying to force the sum into the type of the field being summed even if the database returns it in a larger type.

The projection portion of the criteria looks like this:
List<Object[]> roleSummaries = session.createCriteria(PhysicalDisk.class)
.setProjection(Projections.projectionList()
.add(Projections.groupProperty(PhysicalDisk_.role), "role")
.add(Projections.rowCount(), "count")
.add(Projections.sum(PhysicalDisk_.totalBytes), "space")
)
.createCriteria(PhysicalDisk_.raidGroup, "raidGroup")
.createCriteria("raidGroup." + RAIDGroup_.plex, "plex")
.add(Restrictions.eq("plex." + Plex_.diskAggregate, diskAggregate))
.list();

and the exception I am getting is:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLDataException: '12000010002048860160' in column '3' is outside valid range for the datatype BIGINT.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.6.0_21]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) ~[na:1.6.0_21]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) ~[na:1.6.0_21]
at java.lang.reflect.Constructor.newInstance(Constructor.java:513) ~[na:1.6.0_21]
at com.mysql.jdbc.Util.handleNewInstance(Util.java:409) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.Util.getInstance(Util.java:384) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1027) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:929) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.ResultSetImpl.throwRangeException(ResultSetImpl.java:7970) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.ResultSetImpl.parseLongAsDouble(ResultSetImpl.java:7254) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2944) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2909) ~[mysql-connector-java.jar:na]
at com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:3021) ~[mysql-connector-java.jar:na]
at org.apache.commons.dbcp.DelegatingResultSet.getLong(DelegatingResultSet.j开发者_运维知识库ava:278) ~[commons-dbcp.jar:1.4]
at org.apache.commons.dbcp.DelegatingResultSet.getLong(DelegatingResultSet.java:278) ~[commons-dbcp.jar:1.4]
at org.hibernate.type.descriptor.sql.BigIntTypeDescriptor$2.doExtract(BigIntTypeDescriptor.java:61) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:64) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:249) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:234) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.criteria.CriteriaLoader.getResultColumnOrRow(CriteriaLoader.java:148) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:639) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.Loader.doQuery(Loader.java:829) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.Loader.doList(Loader.java:2533) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.Loader.list(Loader.java:2271) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) ~[hibernate-core.jar:3.6.0.Final]
at com.netapp.dfm.entity.storage.WAFLDiskEntityManager.findDiskPhysicalSummaryForCluster(WAFLDiskEntityManager.java:153) ~[dfm-data-access.jar/:na]
at com.netapp.dfm.entity.storage.WAFLDiskEntityManager$$FastClassByCGLIB$$707d513f.invoke(<generated>) ~[cglib-nodep.jar:na]
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191) ~[cglib-nodep.jar:na]
...


Beware: NOT TESTED

Projections.sum()'s implementation is the following:

return new AggregateProjection("sum", propertyName);

And AggregateProjection uses the type of the property as the type returned by the function (sum)

You could instead use a custom subclass of AggregateProjection where the getTypes method is overridden to return new Type[] {BigIntegerType.INSTANCE} instead of the type of the summed property.


The problem stems from the fact that the database is trying to fit the sum of the BIGINT fields into a BIGINT which is too small to contain the value (which also does not fit into a java.lang.Long).

To circumvent this problem you can replace your sum projection with the following:

Projections.sqlProjection(
    "cast(sum({alias}.PHYSICAL_DISK) as number(30)) as SPACE", 
    new String[] { "SPACE" }, 
    new Type[] { BigIntegerType.INSTANCE })

(assuming that the property "physicalDisk" is mapped onto the "PHYSICAL_DISK" column on your table).

Note, I've only tested this in H2 rather than MySQL, but considering MySQL does have a cast operator, the principle should be the same.


Hibernate has changed behavior in return types for Projections.sum between versions. If you are using a version of Hibernate before 3.5, sum will return an Integer. 3.5 and above, it will return a Long. See this post for more information. If you are not at 3.5, migrating to the newer version might alleviate your issue.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜