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 :

[hibernate 3] many-to-many, je tourne en rond


Sujet :

Hibernate Java

  1. #1
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 67
    Points : 50
    Points
    50
    Par défaut [hibernate 3] many-to-many, je tourne en rond
    Bonjour,
    Voilà mon soucis : je veux faire une association bidirectionnelle plusieurs à plusieurs et quoi que je fasse je tombe sur LazyInitializationException.

    J'ai donc les tables USER, ROLE et REL_USER_ROLE(jointure).

    J'ai compris que les collections sont chargées de façon "Lazy", c'est à dire à la demande donc il faut une session toujours ouverte quand on veut y accéder. OK.
    J'ai également cru comprendre qu'il faut toujours implémenter les fonctions equals/hashCode dans le JavaBean. OK

    Voilà des extraits des codes :
    User.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
     
    public class User
    {
    ...
      private Collection<Role> roles = new HashSet<Role>();
     
      public int hashCode()
      {
        Iterator iRole = getRoles().iterator(); //ligne 65
        while(iRole.hasNext()) {
          result += 17 * (iRole.next() != null ? iRole.next().hashCode() : 1);
        }
      }
    ...
    }
    Role.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
     
    public class Role
    {
    ...
      private Collection<User> users = new HashSet<User>();
     
      public int hashCode()
      {
        Iterator iUser = getUsers().iterator(); //ligne 41
        while(iUser.hasNext()) {
          result += 17 * (iUser.next() != null ? iUser.next().hashCode() : 1);
        }
      }
    ...
    }
    User.hbm.xml
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    <hibernate-mapping>
      <class table="USER" name="test.User">
        <id access="property" name="id">
          <generator class="native"/>
        </id>
    ...
        <set table="REL_USER_ROLE" cascade="all" name="roles">
          <key column="user_id" not-null="true"/>
          <many-to-many column="role_id" class="test.Role"/>
        </set>
    ...
      </class>
    </hibernate-mapping>
    Role.hbm.xml
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    <hibernate-mapping>
      <class table="ROLE" name="test.Role">
        <id access="property" name="id">
          <generator class="native"/>
        </id>
    ...
        <set table="REL_USER_ROLE" inverse="true" cascade="all" name="users">
          <key column="role_id" not-null="true"/>
          <many-to-many column="user_id" class="test.User"/>
        </set>
      </class>
    </hibernate-mapping>
    Corps de la fonction de test (obtenir la liste des roles) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    tx = session.beginTransaction();
    Query q = session.createQuery( "from ROLE aRole left join fetch aRole.users" );
    resultset = q.list();
    tx.commit();
    Et le message d'erreur :
    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
     
    May 5, 2010 9:38:18 AM org.hibernate.LazyInitializationException <init>
    SEVERE: illegal access to loading collection
    org.hibernate.LazyInitializationException: illegal access to loading collection
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:341)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    	at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
    	at test.Role.hashCode(Role.java:41)
    	at java.util.HashMap.put(HashMap.java:372)
    	at java.util.HashSet.add(HashSet.java:200)
    	at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
    	at org.hibernate.collection.PersistentSet.endRead(PersistentSet.java:329)
    	at org.hibernate.engine.loading.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:237)
    	at org.hibernate.engine.loading.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:222)
    	at org.hibernate.engine.loading.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:195)
    	at org.hibernate.loader.Loader.endCollectionLoad(Loader.java:877)
    	at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:865)
    	at org.hibernate.loader.Loader.doQuery(Loader.java:729)
    	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
    	at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
    	at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:36)
    	at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:565)
    	at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:60)
    	at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716)
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    	at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
    	at test.User.hashCode(User.java:65)
    	at java.util.HashMap.put(HashMap.java:372)
    	at java.util.HashSet.add(HashSet.java:200)
    	at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
    	at org.hibernate.collection.PersistentSet.endRead(PersistentSet.java:329)
    	at org.hibernate.engine.loading.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:237)
    	at org.hibernate.engine.loading.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:222)
    	at org.hibernate.engine.loading.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:195)
    	at org.hibernate.loader.Loader.endCollectionLoad(Loader.java:877)
    	at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:865)
    	at org.hibernate.loader.Loader.doQuery(Loader.java:729)
    	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
    	at org.hibernate.loader.Loader.doList(Loader.java:2220)
    	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
    	at org.hibernate.loader.Loader.list(Loader.java:2099)
    	at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:378)
    	at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:338)
    	at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:172)
    	at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1121)
    	at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
    	at test.USER_ManagementTest.getAllRoles(USER_ManagementTest.java:71)
    	at test.USER_ManagementTest.main(USER_ManagementTest.java:209)
    En fait on dirait que ça tourne en rond : quand je veux la liste des roles, hashCode va chercher les users de chaque role, et pour chaque user hibernate va chercher ces roles ...etc

    Je n'ai trouvé sur le net aucun exemple complet de relation many-to-many.
    Voyez-vous le problème ? Que me conseillez-vous?

  2. #2
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 67
    Points : 50
    Points
    50
    Par défaut
    Je me demande si il ne faudrait tout simplement pas faire de test sur les collections dans hashCode ??

  3. #3
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 274
    Points : 4 141
    Points
    4 141
    Par défaut
    J'imagine que si, pour tester, tu vires tes deux méthodes hashcode, ça devrait fonctionner, non ?

  4. #4
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 67
    Points : 50
    Points
    50
    Par défaut oui
    En effet, lorsque dans les fonctions hashCode je supprime le traitement des Collections, ça marche...

  5. #5
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 274
    Points : 4 141
    Points
    4 141
    Par défaut
    Change donc ton implémentation de hashCode pour qu'elle ne tienne pas compte des collections mais simplement des attributs simples.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 82
    Points : 82
    Points
    82
    Par défaut
    Oui en effet, il faut changer ta methode hashCode .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public int hashCode()
      {
        Iterator iRole = getRoles().iterator(); //ligne 65
        while(iRole.hasNext()) {
          result += 17 * (iRole.next() != null ? iRole.next().hashCode() : 1);
        }
      }
    Tu vas tuer ton application, surtout si après tu utilises une HashMap avec des objets User par exemple. Je te conseille de renvoyer simplement la clé primaire de User qui est unique dans une table.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 82
    Points : 82
    Points
    82
    Par défaut
    http://people.apache.org/~bayard/com...deBuilder.html

    Que pensez-vous de cette classe pour générer un hashCode ?

  8. #8
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 67
    Points : 50
    Points
    50
    Par défaut Seule la clé primaire, il faut pas
    Miday, d'après l'article ici:
    http://community.jboss.org/wiki/EqualsandHashCode
    ou
    Il ne faut pas utiliser uniquement la clé primaire.
    Je peux cependant utiliser d'autres attributs (comme le login qui est unique aussi par contrainte BD, la "business key" ).

    D'après la doc sun ici (item 8), je ne sais pas trop si pour une Collection il faut ou si il NE faut PAS traiter.

    Pour info, dans une relation unidirectionnelle, la présence des Collection dans hashCode ne posaient pas de soucis...

    Bon, bref, à défaut de comprendre, je vais virer les Collections de la fonction hashCode dans ce cas.

  9. #9
    Membre du Club
    Inscrit en
    Janvier 2008
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 67
    Points : 50
    Points
    50
    Par défaut HashCodeBuilder
    Miday,
    en regardant des sources de HashCodeBuilder, on voit que ça suit les recommandations de ce qui est dit dans la doc sun dont parle juste avant.

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 82
    Points : 82
    Points
    82
    Par défaut Pour les collections Sun , le hashCode est implémenté dans leurs classes abstraites
    Oui c'est vrai que utiliser simplement l'id est un peu simpliste. Donc il faut utiliser une business key en combinaison linéaire avec des autres attributs primitifs et aussi des éléments du tableaux car d'après le document il faut traiter les tableaux :
    vii. If the field is an array, treat it as if each element were a separate field.
    That is, compute a hash code for each significant element by applying
    these rules recursively, and combine these values as described in
    step 2.b.

    Pour les collections Sun , le hashCode est implémenté dans leurs classes abstraites et eux, il traite cela comme un tableau.
    Si on utilise les HashSet par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    java.util.Set<String> set = new HashSet<String>();
    set.hashCode(); // retourne un hashCode.
    java.util.HashSet hérite de AbstractSet qui elle implémente le hashCode().

    En ce qui concerne les avantages d'utiliser HashCodeBuilder, je pense qu'il faut l'utiliser que quand on a énormément d'attributs et qu'on ne veut pas perdre de temps

Discussions similaires

  1. Un peu de mal a comprendre le concepte "one-to-many" et "many-to-many"
    Par chriscoolletoubibe dans le forum Hibernate
    Réponses: 4
    Dernier message: 29/03/2007, 18h50
  2. [Hibernate] Relation one to many
    Par BRAUKRIS dans le forum Hibernate
    Réponses: 2
    Dernier message: 23/08/2006, 11h51
  3. [Hibernate] delete sur un many-to-many
    Par Gob4 dans le forum Hibernate
    Réponses: 1
    Dernier message: 10/05/2006, 16h26
  4. [hibernate] relation one-to-many avec plusieurs clés
    Par seb_fou dans le forum Hibernate
    Réponses: 6
    Dernier message: 16/03/2006, 14h47
  5. [hibernate]relation many-to-many
    Par quilo dans le forum Hibernate
    Réponses: 5
    Dernier message: 20/12/2005, 10h07

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