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 :

Probleme autoincrement id


Sujet :

Hibernate Java

  1. #1
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut Probleme autoincrement id
    Bonjour.

    Je suis en train de découvrir hibernate (hibernate-release-4.3.1.Final.jar) et je rencontre un problème lors de la sauvegarde d'un objet.

    En base de données, j'ai la table CPTE_TARIF qui contient un id.
    Cette table appartient à l'utilisateur CPTEADM.

    L'application se connecte via l'utilisateur CPTECLI qui a les droits de lecture/insert/update/delete sur toutes les tables de CPTEADM.

    Le mapping est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     <class name="hibernate.CpteTarif" schema="CPTEADM" table="CPTE_TARIF">
      <id name="tarId" type="long">
       <column name="TAR_ID" precision="22" scale="0"/>
       <generator class="increment"/>
      </id>
    ...
    Lors de la lecture d'un objet via hibernate :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    List<CpteTarif> list2 = session.createQuery("from CpteTarif").list(); 
    ou
     list2 = session.createCriteria(CpteTarif.class).list();
    le sql généré est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    select 
    cptetarif0_.TAR_ID as TAR_ID1_0_, cptetarif0_.TAR_LIBELLE as TAR_LIBELLE2_0_, 
    cptetarif0_.TAR_NOM_ARTICLE as TAR_NOM_ARTICLE3_0_, cptetarif0_.TAR_GROUPE_MARCHANDISE as TAR_GROUPE_MARCHAN4_0_ 
    from CPTEADM.CPTE_TARIF cptetarif0_
    --> on voit bien que le nom de user propriétaire est marqué devant le nom de la table. Le SQL fonctionne donc.


    Par contre, lors de la création d'un objet via le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    CpteTarif toto = new CpteTarif("libelle", "nomA", "grpM",new HashSet<CpteTarifvaleur>());
    session.beginTransaction();
    session.save(toto);
    session.getTransaction().commit();
    Le premier sql généré est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Hibernate: select max(TAR_ID) from CPTE_TARIF
    --> on voit que le nom du user n'est pas marqué devant la table.
    On a donc une erreur oracle "ORA-00942: Table ou vue inexistante" tout à fait normale.
    Une solution serait alors de mettre des "public synonyme" sur la base, mais ce n'est pas ce qui est souhaité.

    Pourquoi hibernate ne mets pas le nom du user "tout seul" lors de la recherche du max, ce qu'il fait pour toutes les autres requêtes.

    Merci d'avance.

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Je suppose que ce generateur ne supporte pas les schemas (bug?). De toutes façons, il n'est pas recommandable comme generator, vu qu'il nécessite que personne d'autre n'accède à la table en même temps.

    Tu peux essayer ça pour contourner
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     <class name="hibernate.CpteTarif" table="CPTEADM.CPTE_TARIF">
      <id name="tarId" type="long">
       <column name="TAR_ID" precision="22" scale="0"/>
       <generator class="increment"/>
      </id>

  3. #3
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Alors, de mémoire, avec les tables Oracle j'utilisais un generateur de type "SEQUENCE"
    Au niveau mapping, ça ressemble à ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <generator class="sequence">
          <param name="sequence">USERS_1SQ</param>
    </generator>
    Pour le paramétrage du séquenceur dans Oracle, il faut regarder la doc, je ne m'en souviens plus
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    pour l'utilisation des sequences ou max(id), je verrai ce que j'utliserai.

    pour le problème d’accès à la table d'un autre user et afin que ca fonctionne dans tous les cas, il suffisait de mettre dans le fichier hibernate.cfg.xml:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <property name="hibernate.default_schema">CPTEADM</property>
    .

    Par contre, j'ai une autre question, peut être que vous allez pouvoir me répondre, vu que c'est très simple

    un Tarif contient une liste de valeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    <set name="cpteTarifvaleurs" table="CPTE_TARIFVALEUR" inverse="true" lazy="true" fetch="select">
                <key>
                    <column name="TAR_ID" precision="22" scale="0" not-null="true" />
                </key>
                <one-to-many class="hibernate.CpteTarifvaleur" />
            </set>
    Pour ajouter (et sauvegarder) une valeur à un tarif, comment faut-il faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    CpteTarif montarif =  (CpteTarif) session.get(CpteTarif.class, 2);
    CpteTarifvaleur val = new CpteTarifvaleur(montarif, new Date(), null, new BigDecimal(20));
    session.getTransaction().begin();
    session.save(val);
    session.getTransaction().commit();
    --> cela fonctionne, cela insert bien une ligne de valeur dans la table CPTE_TARIFVALEUR
    ensuite, pour recharger le tarif (avec sa liste de valeur à jour), il suffit de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    montarif=(CpteTarif) session.get(CpteTarif.class, 2);
    Par contre, si je fait cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    CpteTarifvaleur val2 = new CpteTarifvaleur(montarif, new Date(), null, new BigDecimal(30))
    montarif.getCpteTarifvaleurs().add(val2);
    session.getTransaction().begin();
    session.save(montarif);
    session.getTransaction().commit();
    --> cela sauvegarde le tarif, mais ne sauvegarde pas la liste de valeurs dans la table CPTE_TARIFVALEUR
    Est-ce normal?

    Cdt

  5. #5
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Il faut préciser l'attribut "cascade" dans ton mapping de tarif (pour la liste)
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    C'est super cette fonctionnalité.

    Par contre, je suppose que cela doit être utilisé avec parcimonie afin de ne pas mettre à jour l'ensemble des listes pouvant découler?

    Sauf si que vu qu'hibernate fait les requête SQL que s'il détecte un update/insert/delete à faire, cela peut être utile d'etre régulièrement en cascade?

    Qu'en pensez vous? ou conseillez vous avec du recul?

    Cdt

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    ça ne met à jour que les listes qui ont changé, donc en général, on met le cascade. Il est rare de modifier un objet pour au final se dire "je ne vais sauver qu'un partie de l'objet finalement"

  8. #8
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Avec le recul, je dirais que seules les listes qui ont un intérêt fonctionnel sur l'entité concernée devrait être précisées, pour le reste, il y a l'application et des requêtes ciblées.
    Prenons un exemple simple : une commande.
    La Commande à une liste de Lignes, chaque Ligne référence un Article.
    On a donc une contrainte d'intégrité référentielle de ligne sur commande et de ligne sur article.
    Si on laisse faire le mapping par un outil comme celui de jboss-tools, on aura une liste d'objets <Ligne> dans Commande, une relation type many-to-one de Article dans Ligne et une liste d'objets <Ligne> dans Article....
    Autant dire que cette dernière n'a pas de sens... au niveau du mapping bien sûr... il peut être tout à fait intéressant de savoir si un Article est référencé dans une Ligne
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    Dans votre exemple :
    La Commande à une liste de Lignes, chaque Ligne référence un Article.

    Il est donc intéressant de mettre cascade au niveau de la relation Commande.liste<Lignes> : comme cela les lignes se mettent à jour lors de la modification d'une commande
    mais il est moins intéressant de mettre cascade sur la relation Ligne.Article : comme cela, il n'y a pas de mise à jour en cascade sur l'article lorsqu'on crée une ligne de commande référençant un article.
    Et bien sur, pas intéressant de mettre cascade sur la relation (que je dirais relation "inverse" quand on par de la commande) Article.liste<Ligne>.

    Est-ce bien cela?

    Pour info, j'utilise jboss-tools via eclipse pour générer le mapping et les classes "Objet" et les "ObjetHome".
    Pour enrichir les classes "Home" afin de rajouter d'autres requêtes sur ce même objet, il suffit donc d'étendre cette class Home générée afin de ne pas perdre les ajouts manuel lors d'une nouvelle génération?


    Cdt

  10. #10
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    C'est tout à fait cela... cascade sur Commande, et surtout pas ailleurs...
    Dans cet exemple, on gère tout sur l'objet Commande, en aucun cas par les objets Ligne... même une modification/suppression d'une ligne.
    On pourrait avoir d'autres exemples où la modification d'un objet d'une sous-liste pourrait avoir un sens, encore que... pas si sûr...

    J'utilise également jboss-tools pour créer les entités, dans un environnement EJB/JPA, ceci dit, je génère toujours dans un répertoire de travail et je copie les modifications vers le projet cible à la main, il y a plein de chose que l'outil ne sait pas faire (à moins que ce ne soit moi qui ne sache pas lui faire faire... tout à fait plausible ) et que je ne veux pas remettre en cause comme les objets "@Embedded"

    Dans un environnement EJB, on passe plutôt par une Façade (voir le design pattern) et c'est elle qui référence les différentes "sous-façades" (encapsulation). L'application ne voit que la façade.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  11. #11
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    Pour l'instant, je ne fait que des tests via un main(), mais normalement, ce serait pour mettre sur un appli web avec Tomcat (pour éviter de se faire les DAO à la main)

    Et j'ai une derniere question:
    vaut il mieux gérer le code comme dans les précédents exemples (cad en dehors des home)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    //lecture :
    CpteTarifvaleur val2 = new CpteTarifvaleur(montarif, new Date(), null, new BigDecimal(30))
     
    //enregistrement :
    montarif.getCpteTarifvaleurs().add(val2);
    session.getTransaction().begin();
    session.save(montarif);
    session.getTransaction().commit();
    :

    ou le faire via les home:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //lecture
    CpteTarif montarif =  (CpteTarif) session.get(CpteTarif.class, 2);
    remplacé par 
    CpteTarif montarif =  new CpteTarifHome().findById(2)
     
    //enregistrement
    session.getTransaction().begin();
    session.save(montarif);
    session.getTransaction().commit();
    remplacé par : 
    new CpteTarifHome().attachDirty(monTarif); //attachDirty ou merge
    PS : je ne maitrise pas la différence entre save et saveOrUpdate, mon besoin n'étant que de lire, enregistrer en base

    Cdt

  12. #12
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Alors, pour moi, tout doit se faire via les DAO. La seule chose qui circule, c'est l'entity...

    J'ai un code générique pour les DAO Hibernate si ça t'intéresse, ça réduit le code au spécifique.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  13. #13
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    Je suis intéressé d'avoir un petit exemple car c'est n'est pas évident de voir où et comment mettre son code en plus de l'objet généré Objet et ObjetHome
    Vous voulez mon mail en PV pour m'envoyer un zip?

  14. #14
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Dans l'ordre, une classe utilitaire pour récupérer la session
    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
    49
    50
    51
    52
    53
    54
     
    public class HibernateUtils 
    {
        private static final SessionFactory sessionFactory;
        private static final Logger logger = Logger.getLogger(HibernateUtils.class);
     
        static 
        {
            try 
            {
                logger.debug("Création Session Factory Hibernate");
                sessionFactory = new Configuration().setInterceptor(new EntityInterceptor()).configure().buildSessionFactory();
            } 
            catch (HibernateException ex) 
            {
                logger.error("Erreur lors de la création de la Session Factory Hibernate : " + ex.getMessage());
                throw new RuntimeException("Problème de configuration : " + ex.getMessage(), ex);
            }
        }
     
        public static final ThreadLocal<Session> session = new ThreadLocal<Session>();
     
        /**
         *    Récupération de la session Hibernate
         */
        public static Session currentSession() throws HibernateException 
        {
            Session s = (Session) session.get();
     
            // Ouvre une nouvelle Session, si ce Thread n'en a aucune
            if (s == null) 
            {
                logger.debug("Acquisition d'une nouvelle Session Hibernate pour le Thread " + Thread.currentThread().hashCode());
                s = sessionFactory.openSession();
                session.set(s);
            }
     
            logger.debug("Récupération de la Session Hibernate " + s.hashCode() + " pour le Thread " + Thread.currentThread().hashCode());
            return s;
        }
     
        /**
         *    Fermeture de la session Hibernate
         */
        public static void closeSession() throws HibernateException 
        {
            Session s = (Session) session.get();
            if ( s == null ) return ;
     
            logger.debug("Fermeture de la Session Hibernate " + s.hashCode() + " pour le Thread " + Thread.currentThread().hashCode());
            session.set(null);
            s.close();
        }  
    }
    L'interface et l'implémentation générique des DAO
    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
     
     
    public interface GenericDaoInterface<T, I extends Serializable>
    {
        T get(I id);
     
        List<T> listAll();
     
        T save(T t);
     
        T update(T t);
     
        void delete(I id);
     
        void delete(T t);
     
    }
    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
     
    public abstract class GenericDao<T, I extends Serializable> implements GenericDaoInterface<T, I>
    {
        protected Class<? extends T> clazz;
        private Logger logger = Logger.getLogger("GenericDao");
     
        /*
         * Constructeur générique
         */
        @SuppressWarnings("unchecked")
        protected GenericDao()
        {
            this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
     
        }
     
        /*
         * Récupération de la session Hibernate
         */
        public Session getHibernateSession()
        {
            return HibernateUtils.currentSession();
        }
     
        /*
         * Récupération de l'objet pour la clé recherchée
         */
        @SuppressWarnings("unchecked")
        public T get(I id)
        {
            logger.debug("get(id) " + id);
            return (T) getHibernateSession().get(clazz, id);
        }
     
        /*
         * Suppression de l'objet pour la clé recherchée
         */
        public void delete(I id)
        {
            logger.debug("delete(id) " + id);
            delete(get(id));
        }
     
        /*
         * Suppression de l'objet
         */
        public void delete(T t)
        {
            logger.debug("delete(T) : " + t.getClass().getName());
            getHibernateSession().delete(t);
        }
     
        /*
         * Sauvegarde de l'objet dans la base de données
         */
        @SuppressWarnings("unchecked")
        public T save(T t)
        {
            logger.debug("save(T) : " + t.getClass().getName());
            Serializable key = getHibernateSession().save(t);
            T r = (T)getHibernateSession().get(clazz, key);
            return r;
        }
     
        /*
         * Mise à jour de l'objet dans la base de données
         */
        @SuppressWarnings("unchecked")
        public T update(T t)
        {
            logger.debug("update(T) : " + t.getClass().getName());
            getHibernateSession().update(t);
            Serializable key = getHibernateSession().getIdentifier(t); 
            T r = (T)getHibernateSession().get(clazz, key);
            return r;
        }
     
     
        /*
         * Récupération de tous les enregistrements
         */
        @SuppressWarnings("unchecked")
        public List<T> listAll()
        {
            logger.debug("listAll()");
            return getHibernateSession().createCriteria(clazz).list();
        }
    }
    Une classe DAO "Réelle" (dans cet exemple, le numéro du client est calculé, d'où la surcharge de save)
    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
     
    public class ClientDao extends GenericDao<Client, String> implements GenericDaoInterface<Client, String>
    {
        private static ClientDao instance;
        private static final Logger logger = Logger.getLogger(ClientDao.class);
     
        private ClientDao()
        {
            super();
        }
     
        public static synchronized ClientDao getInstance()
        {
            if (instance == null)
            {
                instance = new ClientDao();
            }
            return instance;
        }
     
        /**
         * Génération de la clé primaire
         */
        public String getNextUid()
        {
            String uid = null;
            try
            {
                PreparedStatement pstmt1 = HibernateUtils.currentSession().connection().prepareStatement("select prefix,uid from compteurs where tableName='client'");
                PreparedStatement pstmt2 = HibernateUtils.currentSession().connection().prepareStatement("update compteurs set uid=? where tableName='client'");
                ResultSet rs = pstmt1.executeQuery();
                if (rs.next())
                {
                    int count = rs.getInt("uid");
                    String prefix = rs.getString("prefix");
                    count += 1;
                    pstmt2.setInt(1, count);
                    pstmt2.executeUpdate();
                    uid = prefix + count;
                }
            }
            catch (Exception e)
            {
                logger.error(e.toString());
            }
            return uid;
        }
     
        @Override
        /**
         * Sauvegarde d'un nouvel enregistrement : génération et affectation de la clé primaire
         */
        public synchronized Client save(Client t)
        {
            t.setUid(getNextUid());
            return super.save(t);
        }
     
        @SuppressWarnings("unchecked")
        public List<Client> listByCriteria(Map<String, Object> map, int maxResult)
        {
            Criteria query = getHibernateSession().createCriteria(clazz);
            query.setMaxResults(maxResult);
     
            for (String column : map.keySet())
            {
                Object value = map.get(column);
     
                if (value != null)
                {
                    if (value instanceof String)
                    {
                        String v = Converters.replaceJocker((String)value);
                        if (v.indexOf("%") == -1) v += "%";
                        query.add(Restrictions.ilike(column, v));    
                    }
                    else
                    {
                        query.add(Restrictions.eq(column, value));
                    }
     
                }
            }
            return query.list();
        }
    }
    et enfin un exemple avec un contrôleur struts1
    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
     
    ...
        public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
                throws Exception
        {
            try
            {
                DetailForm _form = (DetailForm) form;
     
                HibernateUtils.currentSession().beginTransaction();
                if (FormUtils.getFormDisplayMode(request, form) == FormUtils.CREATE_MODE)
                {
                    ClientDao.getInstance().save(_form.getClient());
                }
                else
                {
                    ClientDao.getInstance().update(_form.getClient());
                }
                HibernateUtils.currentSession().getTransaction().commit();
     
                _form.setCreatePending(false);
                forward = mapping.findForward(FORWARD_SAVED);
            }
            catch (Exception e)
            {
                request.setAttribute("ERROR_MESSAGES", e.toString());
                forward = mapping.findForward(FORWARD_DEFAULT);
            }
            return forward;
        }
    ...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  15. #15
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    Merci pour cet exemple, je vais pouvoir regarder cela.

    Une question bete, pourquoi DAO.getInstance? et pas new DAO(). Ca revient peut etre au même? sauf qu'il y a qu'une instance dans l'application?

    Et une remarque, la methode listByCriteria pourait-tout à fait être dans le GenericDAO.

  16. #16
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Pour le DAO.getInstance(), c'est le pattern singleton, une seule instance, partagée

    Pour la méthode listByCriteria, il y aurait peut-être quelques ajouts à prévoir pour la rendre vraiment générique, mais elle n'en est pas loin et rien n'empêcherait de la mettre dans la partie générique, quitte à la redéfinir pour les cas non couverts.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  17. #17
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    En reprenant le code, est ce normal d'avoir une erreur sur la methode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        protected GenericDao()
        {
            this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
     
        }
    car "ParameterizedType n'est pas reconnu comme type valide" (car je suis en java 6?)

    Je vais donc essayer sans mettre ce constructeur

  18. #18
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    non, ça devrait passer en java 6, tu as mis les jar dans ton path ?
    Il devrait avoir les imports suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    import java.io.Serializable;
    import java.lang.reflect.ParameterizedType;
    import java.util.Collection;
    import java.util.List;
    import org.apache.log4j.Logger;
    import org.hibernate.Criteria;
    import org.hibernate.Session;
    import org.hibernate.criterion.Restrictions;
    import com.obia.safe.hibernate.utils.HibernateUtils;    <--- celui-ci sera forcément différent
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  19. #19
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    C'est bon, éclipse ne me proposait pas l'import de la bibliotheque.

    Par contre, en utilisant votre base, j'ai un probleme sur la mise à jour.

    J'a mon écran avec mon formulaire de modification qui appelle via struts mon action de cration/suppression d'un locataire

    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
     
     public String validerLocataire() throws Exception
    	 {
    		 String codeRetour=INPUT;
     
    		 if(locataire.getLocId()==0)
    		 {
    			 log.debug("validation creation d'un locataire");
     
    			 if(hasErrors() == false)
    			 {
    				 log.debug("creation du locataire : "+locataire.getLocRaisonSociale());
    				 HibernateUtil.currentSession().beginTransaction();
    				 CpteLocataireDao.getInstance().save(locataire);
    				 HibernateUtil.currentSession().getTransaction().commit();
    				 codeRetour=SUCCESS;
    			 }
    		 }
    		 else
    		 {
    			 if(hasErrors() == false)
    			 {
    				 log.debug("mise à jour du locataire : "+locataire.getLocRaisonSociale());
    				 HibernateUtil.currentSession().beginTransaction();
    				 CpteLocataireDao.getInstance().update(locataire);
    				 HibernateUtil.currentSession().getTransaction().commit();
    				 codeRetour=SUCCESS;
    			 }
     
    		 }
     
    		 if(hasErrors()==false && INPUT.equals(codeRetour))
    		 {
    			 addActionError(getText("error.baseDeDonnees"));
    		 }
     
    		 return codeRetour;
    	 }
    En utilisant le mode "debugage", je vois bien que locataire.getLocId() est bien connu (c'est l'identifiant de ma table) --> Je suis bien en modification
    Lors de l'appel à la fonction update, j'ai l'erreur suivante :
    org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [cpte.hibernate.CpteLocataire#5]

    Est-ce normal?

    Par contre, si j'appelle la fonction "save", (au lieu d'update) une création se fait (alors que je voudrait modifier).

    Hibernate n'est pas capable de décider tout seul s'il doit créer ou enregistrer un nouvel élément?

    Merci d'avance pour votre aide qui me permettra de faire la suite comme un grand

  20. #20
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Je ne pense pas que le problème vienne du code que je t'ai fourni, c'est plus dans la succession des opérations qu'il devrait y avoir un problème.
    Ce qui est sûr, c'est que c'est un update(...) que tu dois faire pour une modification et un save(...) pour créer un enregistrement;

    Quand fermes-tu la session hibernate ? Dans le fragment de code, je ne vois pas la fermeture, du coup, tu traines peut-être une session depuis n request...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. probleme champ autoincrement
    Par Daniela dans le forum Modélisation
    Réponses: 1
    Dernier message: 23/12/2010, 11h37
  2. probleme avec le champs de type "autoincrement"
    Par hayat2 dans le forum Bases de données
    Réponses: 2
    Dernier message: 09/05/2010, 09h28
  3. Probleme avec autoincrement Mysql Jsf
    Par dalidali86 dans le forum Requêtes
    Réponses: 0
    Dernier message: 10/09/2009, 00h18
  4. Réponses: 4
    Dernier message: 25/11/2008, 18h34
  5. [Kylix] Probleme d'execution de programmes...
    Par yopziggy dans le forum EDI
    Réponses: 19
    Dernier message: 03/05/2002, 14h50

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