web-dev-qa-db-fra.com

hibernate exception Une valeur nulle a été affectée à une propriété de type primitif

Avoir un problème frustrant avec Hibernate 3.6.9. MS SQL Server 2008. Notez l'exception et la référence d'index de colonne impaire.

La requête HQL elle-même:

Select r from DataStoreReference r join fetch r.container c where r.hash=:hash and r.state=0

La trace de la pile:

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

Maintenant, je comprendrais cela par la logique (et par googler) si ce qui suit n'était pas vrai

a) chaque instanciation de DataStoreReference est brièvement suivie d'un setUsage de System.currentTimeMillis) b) l'élément est marqué comme non nul dans le mappage (voir ci-dessous) c) le tableau exporté affiche les valeurs nulles uniquement dans la colonne f_external. La colonne d'utilisation a des nombres longs parfaitement raisonnables.

Le 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; 

suivi par des getter/setters génériques non modifiés.

Le fichier de mappage:

<?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>
12
MJB

Il s'avère que c'est un bogue avec les dialectes améliorés Hibernate 3.6 MS SQL. Si vous étendez les dialectes SQLServer2005 ou SQLServer2008, vous aurez ce problème. En utilisant l'ancien dialecte SQLServer (qui est à peu près ce qui est livré avec Hibernate 3.3x), vous ne le faites pas. Probablement quelque chose à voir avec le support de la pagination. Soupir

3
MJB

Le message d'erreur est clair: dans au moins une ligne, la colonne f_usage a une valeur nulle. Cette valeur nulle ne peut pas être placée dans un type primitif comme long, car les types primitifs ne peuvent pas représenter null.

L'attribut non nul dans la clause de propriété n'a aucun effet lorsqu'il existe déjà une valeur nulle dans la base de données. L'attribut non nul uniquement est utilisé pour la génération dmd. Mais la colonne f_usage de votre table de base de données t_dsref autorise probablement des valeurs nulles (vérifiez avec desc t_dsref en sql).

Solution: échangez longtemps avec Long:

private Long usage; 

et lorsque vous utilisez la valeur, vous devez gérer la condition nulle, par exemple

if (usage != null) {
  return usage.longValue();
else
  return -1;

(Vous utilisez des getters et des setters pour accéder avec hibernate, donc ce codelet ne doit pas être dans le getter, car dans la base de données une valeur nulle doit continuer à être nulle après une mise à jour, mais vous pouvez le faire dans un deuxième getter que vous utilisez partout ailleurs, ou vous faites un accès au champ pour la mise en veille prolongée.)

Ma recommandation générale: les types de données primitifs ne doivent être utilisés pour les propriétés d'hibernation que si la colonne est marquée NOT NULL dans la base de données.

31
Johanna

De telles erreurs se produisent dans Hibernate lorsque vous utilisez des types primitifs pour certaines colonnes mais que les champs sont nuls dans DB. solutions:

première solution: utiliser les classes Wrapper (entier pour int ...) deuxième solution: définir des valeurs par défaut pour les colonnes.

4
Mr.Q

Hibernate a besoin de quelques révisions pour correspondre aux scénarios réels de développement d'entreprise. L'utilisation d'objets au lieu de primitives entraîne beaucoup plus de problèmes que ce qui est résolu dans ce contexte.

Je code Java EE apps d'entreprise depuis 2002. La meilleure solution à ce cas d'utilisation, en tenant compte du fait que vous avez probablement de nombreuses tables qui référencent des tables de code avec des valeurs nulles est de mettre à jour la base de données si possible.

Par exemple, si vous avez une table de personnes avec une référence à une table de code de génération pour désigner des titres comme junior, senior, etc. et que de nombreuses entrées sont nulles, mettez à jour la table de code pour avoir une référence inconnue, puis mettez à jour les données de table pour tous null pour pointer vers cette référence. Comme la plupart des applications Java EE qui sont grandes et mal codées, vous pouvez essayer de mettre à jour les points d'entrée vers ces tableaux, mais il est très probable que ce soit un gâchis et qu'il puisse y avoir toutes sortes de points d'entrée exécutés à partir de cron emplois, services Web, etc. alors mettez à jour la base de données pour attraper ces valeurs nulles et les mettre par défaut à l'entrée inconnue et vous épargner un mal de tête. dire à hibernate que vous essayez d'appeler un setter avec une primitive, et c'est nul, faites-le simplement 0 ou -1 mais là encore j'ai moins de 20 heures d'expérience en hibernation. Je lis simplement les types d'utilisateurs donc je vais devoir lisez un peu plus et voyez comment ils fonctionnent.

Objets en grand Java Les applications EE sont un cauchemar à l'exécution avec la qualité des codeurs sur le marché aujourd'hui.

1
eric