Reputation: 9389
Having a frustrating problem with Hibernate 3.6.9. MS SQL Server 2008. Note the exception and the odd column index reference.
The HQL Query itself:
Select r from DataStoreReference r join fetch r.container c where r.hash=:hash and r.state=0
The stack trace:
2012-05-16 00:01:22,184 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT.
2012-05-16 00:01:22,186 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT.
2012-05-16 00:01:22,188 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - Invalid column index 14.
2012-05-16 00:01:22,190 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT.
2012-05-16 00:01:22,193 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - The value supplied cannot be converted to BIGINT.
2012-05-16 00:01:22,194 [BackgroundDeletionThread] ERROR org.hibernate.util.JDBCExceptionReporter - Invalid column index 14.
2012-05-16 00:01:22,194 [BackgroundDeletionThread] ERROR com.flipper.utils.ServerErrorHandlerStrategy - reportError: Db :: com.flipper.datastore.workers.BackgroundDeletionThread.executeWork:87 :: EXCEPTION : com.flipper.datastore.exceptions.DBStoreException: Null value was assigned to a property of primitive type setter of com.flipper.datastore.model.DataStoreReference.usage com.flipper.datastore.exceptions.DBStoreException: Null value was assigned to a property of primitive type setter of com.flipper.datastore.model.DataStoreReference.usage
at com.flipper.datastore.impl.hib.HibernateDBStore.getAllReferences(HibernateDBStore.java:301)
at com.flipper.datastore.workers.BackgroundDeletionThread.processEntry(BackgroundDeletionThread.java:165)
at com.flipper.datastore.workers.BackgroundDeletionThread.processSet(BackgroundDeletionThread.java:138)
at com.flipper.datastore.workers.BackgroundDeletionThread.executeWork(BackgroundDeletionThread.java:84)
at com.flipper.datastore.workers.BackgroundDeletionThread.run(BackgroundDeletionThread.java:60)
Caused by: org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of com.flipper.datastore.model.DataStoreReference.usage
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:109)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:583)
at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:229)
at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:3847)
at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:152)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:982)
at org.hibernate.loader.Loader.doQuery(Loader.java:857)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
at org.hibernate.loader.Loader.doList(Loader.java:2542)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
at org.hibernate.loader.Loader.list(Loader.java:2271)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:459)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:365)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1268)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at com.flipper.message.dao.DataStoreDao.getAllReferencesByHash(DataStoreDao.java:136)
at com.flipper.datastore.impl.hib.HibernateDBStore.getAllReferences(HibernateDBStore.java:298)
... 4 more
Caused by: java.lang.IllegalArgumentException
at sun.reflect.GeneratedMethodAccessor556.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:66)
... 21 more
Now, I'd understand this from logic (and from googling) if the following were not true
a) every instantiation of DataStoreReference is shortly followed by a setUsage of System.currentTimeMillis) b) the item is marked not-null in the mapping (see below) c) the exported table shows nulls only in the f_external column. The usage column has perfectly reasonable long numbers.
The POJO:
DataStoreReference
private long id;
private String hash;
private long date;
private long sze;
private long usage;
private int state;
private String external;
private DataStoreContainer container;
followed by generic unmodified getter/setters.
The mapping file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.flippr.datastore.model">
<class name="DataStoreReference" table="t_dsref">
<id name="id">
<column name="ds_reference_id"/>
<generator class="native"/>
</id>
<property name="hash" not-null="true" column="f_hash" lazy="false" index="idx_hash_dsr" type="string" length="128" />
<property name="state" not-null="true" column="f_state" lazy="false" index="idx_hash_dsr,idx_size_dsr,idx_usage_dsr" type="integer"/>
<!-- hibernate hates the name size -->
<property name="sze" not-null="true" column="f_size" lazy="false" index="idx_size_dsr" type="long"/>
<property name="date" not-null="true" column="f_date" lazy="false" type="long"/>
<property name="usage" not-null="true" column="f_usage" lazy="false" index="idx_usage_dsr" type="long"/>
<property name="external" not-null="false" column="f_ext" lazy="false" type="string" length="160" />
<many-to-one name="container" class="com.flipper.datastore.model.DataStoreContainer"
column="entity_id" foreign-key="fk_ds_container_id_dsr" not-found="ignore" not-null="true"/>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.flipper.datastore.model">
<class name="DataStoreContainer" table="t_dscnt">
<id name="id">
<column name="ds_container_id"/>
<generator class="native"/>
</id>
<property name="containerType" column="f_type" index="idx_containerType_dsc" lazy="false" type="integer"/>
<property name="fileCount" column="f_fc" lazy="false" type="long"/>
<property name="deletedCount" column="f_dc" lazy="false" type="long"/>
<property name="path" column="f_path" length="255" lazy="false" type="string"/>
<set cascade="save-update,delete,delete-orphan,all-delete-orphan" inverse="true" name="documents">
<key column="entity_id" />
<one-to-many class="com.flipper.datastore.model.DataStoreReference"/>
</set>
</class>
</hibernate-mapping>
Upvotes: 13
Views: 67001
Reputation: 4524
Such errors happen in Hibernate when you use primitive types for some columns but that fields are null in DB. solutions:
solution One: use Wrapper classes (Integer for int ...) solution Two: define default values for columns.
Upvotes: 5
Reputation: 11
Hibernate needs some revisions to match the real life scenarios of enterprise development. Using objects instead of primitives leads to many more issues than what is solved in this context.
I have been coding Java EE enterprise apps since 2002. The best solution to this use case, taking into account that you probably have many tables that reference code tables with null values is to update the database if possible.
For instance if you have a persons table with a reference to a generation code table to denote titles like junior, Senior, etc and many entries are null, update the code table to have an un-known reference and then update the table data for all nulls to point to that reference. As most Java EE apps that are large and ill-coded you can try and update the entry points to these tables but most likely it's a mess and there may be all sorts of entry points run from cron jobs, web services, etc so update the DB to catch these nulls and default them to the unknown entry and save your self a headache. If your building from scratch this is also a mess with hibernate as it's not very easy from what I can tell to tell hibernate is your trying to call a setter with a primitive, and it's null just make it 0 or -1 but then again I have less than 20 hrs of hibernate experience. I just read up on user types so I'll have to read a bit more and see how they work.
Objects in large Java EE apps are a nightmare at runtime with quality of coders on the market today.
Upvotes: 1
Reputation: 9389
Turns out it is a bug with the enhanced Hibernate 3.6 MS SQL dialects. If you extend SQLServer2005 or SQLServer2008 dialects, you will have this issue. Using the older SQLServer dialect (which is pretty much what shipped with Hibernate 3.3x) you do not. Probably something to do with paging support introduced. Sigh
Upvotes: 3
Reputation: 5293
The error message is clear: In at least one row the column f_usage has a null value. This null value can't be put into a primitive type like long, because primitive types can't represent null.
The not-null attribute in the property clause has no effect when there already is a null value in the database. The not-null attribute only is used for the dmd generation. But the f_usage column of your database table t_dsref probably allows null values (check with desc t_dsref
in sql).
Solution: Exchange long with Long:
private Long usage;
and when using the value you have to handle the null condition, for example
if (usage != null) {
return usage.longValue();
else
return -1;
(You are using getters and setters for access with hibernate, so this codelet should not be in the getter, because in the database a null value should continue to be null after an update, but you can do it in a second getter which you use everywhere else, or you do field access for hibernate.)
My general recommendation: Primitive datatypes should only be used for hibernate properties if the column is marked with NOT NULL in the database.
Upvotes: 33