IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Hibernate Java Discussion :

Problème de génération d'identifiant (Hibernate et H2DB)


Sujet :

Hibernate Java

  1. #1
    Futur Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut Problème de génération d'identifiant (Hibernate et H2DB)
    Bonjour à tous !

    Je me permets de vous faire part du problème qui me fait tourner en rond depuis quelques heures déjà. Je ne suis pas certain de son origine, entre Hibernate ou bien le SGBD utilisé (H2). Désolé par avance si ça n'est pas lié à Hibernate.


    A priori, il s'agit de la méthode session.save(monObjet) qui génère une exception. L'identifiant généré est null, et de fait, à l'insertion, mon SGBD n'est pas content.

    Ce que je ne comprends pas, c'est que normalement, c'est cette méthode qui est censée gérer l'attribution de la clé (à l'aide du generator défini dans le fichier de mapping). J'ai essayé différents generators, mais avec le même succès.

    Ci-dessous les informations relatives à mon problème.

    Merci d'avance !



    Versions des librairies utilisées :

    Hibernate - 3.3.2.GA
    H2 : 1.2.125 (essayé également avec la dernière stable, 1.1.118)


    Classe Personne.java

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    public class Personne {
        private int idPersonne;
        private String prenom;
        private String nom;
        private int age;
     
        public Personne() {
        }
     
     
    	public int getIdPersonne() {
    		return idPersonne;
    	}
    	public void setIdPersonne(int idPersonne) {
    		this.idPersonne = idPersonne;
    	}
     
            public String getPrenom() {
    		return prenom;
    	}
    	public void setPrenom(String prenom) {
    		this.prenom = prenom;
    	}
     
    	public String getNom() {
    		return nom;
    	}
    	public void setNom(String nom) {
    		this.nom = nom;
    	}
     
    	public int getAge() {
    		return age;
    	}
    	public void setAge(int age) {
    		this.age = age;
    	}
     
    }

    Fichier de mapping :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
    	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
      <class name="Personne" table="Personne">
     
      	<id column="id_personne" name="idPersonne" type="int">
    		<generator class="native" />
    	</id>
    	<property column="prenom" name="prenom" type="string"/>
    	<property column="nom" name="nom" type="string"/>
    	<property column="age" name="age" type="int"/>
      </class>
    </hibernate-mapping>
    Le fichier hibernate.cfg.xml : il ne contient rien de particulier - l'accès à la base (qui fonctionne), avec driver & dialecte, la propriété current_session_context_class avec la valeur thread, ainsi que la déclaration du fichier de mapping.


    Le main :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    public class HibernateMain {
     
    	public static void main(String[] args) {
     
                    Personne p = new Personne();
    		p.setAge(1);
    		p.setNom("Subject #1");
    		p.setPrenom("Test");
     
    		try{
    		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
                    session.beginTransaction();
     
                    session.save(p);
     
                    session.getTransaction().commit();
    }
    		catch (HibernateException e) {
    			e.printStackTrace();
    		}

    Et la pile d'exception :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    ATTENTION: SQL Error: 90006, SQLState: 90006
    14 déc. 2009 16:32:27 org.hibernate.util.JDBCExceptionReporter logExceptions
    GRAVE: NULL not allowed for column "ID_PERSONNE"; SQL statement:
    insert into Personne (id_personne, prenom, nom, age) values (null, ?, ?, ?) [90006-124]
    org.hibernate.exception.GenericJDBCException: could not insert: [fr.insee.tuto_hibernate.model.Personne]
    	at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
    	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
    	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    	at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
    	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2176)
    	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2656)
    	at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    	at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
    	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    	at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    	at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    	at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:563)
    	at org.hibernate.impl.SessionImpl.save(SessionImpl.java:551)
    	at org.hibernate.impl.SessionImpl.save(SessionImpl.java:547)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:585)
    	at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:342)
    	at $Proxy0.save(Unknown Source)
    	at fr.insee.tuto_hibernate.main.HibernateMain.main(HibernateMain.java:42)
    Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "ID_PERSONNE"; SQL statement:
    insert into Personne (id_personne, prenom, nom, age) values (null, ?, ?, ?) [90006-124]
    	at org.h2.message.Message.getSQLException(Message.java:111)
    	at org.h2.message.Message.getSQLException(Message.java:122)
    	at org.h2.message.Message.getSQLException(Message.java:75)
    	at org.h2.table.Column.validateConvertUpdateSequence(Column.java:296)
    	at org.h2.table.Table.validateConvertUpdateSequence(Table.java:599)
    	at org.h2.command.dml.Insert.insertRows(Insert.java:116)
    	at org.h2.command.dml.Insert.update(Insert.java:82)
    	at org.h2.command.CommandContainer.update(CommandContainer.java:72)
    	at org.h2.command.Command.executeUpdate(Command.java:209)
    	at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:139)
    	at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:128)
    	at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
    	at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
    	... 22 more

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    comment as-tu créé tes tables?

  3. #3
    Futur Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    Bonjour, et merci pour ta réponse, tchize_

    J'ai créé mes tables à la main via la console de la base de données, avec le script suivant (pour la table Personne).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    CREATE TABLE Personne (id_personne INTEGER,
    					   prenom VARCHAR(30),
    					   nom VARCHAR(30),
    					   age INTEGER,
    					   CONSTRAINT pk_personne PRIMARY KEY(id_personne)) ;

    A noter que je n'ai mis qu'une partie de mon code. Mon projet contient d'autres POJO et fichiers de mapping, mais je n'arrive à faire le session.save() sur aucun objet, donc j'ai élagué pour ne pas saturer mon post. Si besoin, je peux héberger une archive de mon projet.

  4. #4
    Membre à l'essai
    Inscrit en
    Avril 2007
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    As tu essayé de forcer la génération dans le fichier de mapping :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <generator class="increment" />
    Ca pourrait peut-être contourner le problème.
    Après je n'ai jamais travailler avec H2 ...

  5. #5
    Futur Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    Merci pour ta réponse, benoit31.

    J'étais effectivement passé à côté du générateur "increment" quand j'ai essayé d'en changer. L'insertion se passe correctement avec mais malheureusement, à en croire la doc d'Hibernate, c'est une solution qui ne pourra pas être viable pour moi, à cause de ça :

    increment

    Génère des identifiants de type long, short ou int qui ne sont uniques que si aucun autre processus n'insère de données dans la même table. Ne pas utiliser en environnement clusterisé.

    Par contre, j'ai essayé de changer de SGBD, et mon code fonctionne correctement sur une base MySQL. De fait, j'imagine que mon problème vient plus de H2 (ou du moins de son support d'Hibernate) que d'Hibernate directement.

    Je vais essayer de présenter mon problème sur la mailing-list de H2, je viendrai éditer ici si j'obtiens des précisions à ce sujet.

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    Toutes les bases de données ne gèrent pas tous les générateurs d'hibernate, et certains générateur nécessitent une configuration particulière des table, comme les colonne en auto increment sous mysql.

  7. #7
    Futur Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    J'ai fini par résoudre le problème, grâce aux indications de tchize_.

    Compte tenu de ta remarque, j'ai essayé de dropper et de créer la table de différentes manières, avec et sans contraintes, en changeant des types, etc.
    J'ai eu divers résultats, mais systématiquement, Hibernate insérait une valeur null.

    Finalement, j'ai essayé l'outil de génération automatique de DDL d'Hibernate (en mettant à create la propriété hbm2ddl.auto). Et là, miracle, ça marche. Dans la trace, Hibernate affiche TOUJOURS qu'il insère une valeur null, sauf que dans les faits, quand on regarde la table dans le blanc des yeux, la valeur est insérée correctement (avec le generator native, qui est celui que je visais).

    Le SQL généré par Hibernate pour créer la table est le suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    16:12:47,425  INFO SchemaExport:226 - Running hbm2ddl schema export
    16:12:47,425 DEBUG SchemaExport:242 - import file not found: /import.sql
    16:12:47,425  INFO SchemaExport:251 - exporting generated schema to database
    16:12:47,425 DEBUG SchemaExport:377 - drop table Personne if exists
    16:12:47,441 DEBUG SchemaExport:377 - create table Personne (id_personne integer generated by default as identity, prenom varchar(255), nom varchar(255), age integer, primary key (id_personne))
    16:12:47,441  INFO SchemaExport:268 - schema export complete
    Hibernate: insert into Personne (id_personne, prenom, nom, age) values (null, ?, ?, ?)
    N'ayant que des connaissances assez basiques en SQL, est-ce que quelqu'un pourrait m'expliquer les clauses du CREATE TABLE qui font la différence par rapport au mien ? (voir mon deuxième post)
    J'imagine que ça tourne autour de "generated by default as identity", mais je ne dis pas non à une petite précision si quelqu'un peut me la donner

    Dans tous les cas, merci pour votre aide !

  8. #8
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    Citation Envoyé par Schmoo Voir le message
    N'ayant que des connaissances assez basiques en SQL, est-ce que quelqu'un pourrait m'expliquer les clauses du CREATE TABLE qui font la différence par rapport au mien ? (voir mon deuxième post)
    "generated by default as identity,"

    ca laisse ton sgdb générer les identifiant quand tu insère les données

  9. #9
    Futur Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    Ceci explique cela. Hibernate genère bien une valeur null dans tous les cas, sauf que l'option generated by default as identity permet d'obtenir quand même un identifiant, et donc d'éviter de lever l'erreur que j'ai obtenue. Finalement, le problème ne venait ni de H2, ni d'Hibernate, mais bel et bien de ma méconnaissance du SQL

    Merci pour ces précisions, d'ailleurs, merci beaucoup à vous deux pour votre aide !

  10. #10
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    un fait, un peu du sgdb et principalement du format des tables Chaque SGDB a des manière différentes et donc des requetes différente pour créer des id automatiques. Sous oracle, on utilisera un trigger par exemple et "create by default etc..." est spécifique au SGBD utilisé C'est pas du SQL standard.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 22/04/2009, 09h35
  2. [Hibernate Tools]Problème de génération de code !
    Par Kevin12 dans le forum Hibernate
    Réponses: 2
    Dernier message: 05/02/2008, 12h28
  3. Problème identifiant hibernate
    Par kokumbo dans le forum Hibernate
    Réponses: 2
    Dernier message: 15/11/2006, 19h18
  4. Réponses: 2
    Dernier message: 25/09/2005, 21h30
  5. [débutant]Génération d'identifiant
    Par Tarrke dans le forum MFC
    Réponses: 8
    Dernier message: 29/04/2005, 13h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo