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 :

Many-to-one et lazy loading


Sujet :

Hibernate Java

  1. #1
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut Many-to-one et lazy loading
    Hello, voilà je viens poster parce que je commence à me prendre sérieusement la tête ^^

    Je suis en train d'optimiser mon applic et je suis tombé sur un problème que je n'arrive pas à résoudre...

    Soit ce mapping pour Phone:

    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
     
     
    ...
     
      <class name="Phone" table="ACTOR_PHONE">
        <id name="id" column="ID" type="long">
          <generator class="native">
            <param name="sequence">PH_SEQUENCE</param>
          </generator>
        </id>
     
        <many-to-one name="actor" class="Actor" column="ACTOR_ID"  
          not-null="true" foreign-key="ACT_PH_FK"/>
     
        <many-to-one name="declaration" column="DECLARATION_ID"
          class="be.xxx.yyy.core.data.model.file.Declaration"  
          foreign-key="DECL_PH_FK" />
     
    ...
    J'écris un test unitaire et je l'exécute avec le show_sql à true juste pour voir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
            Actor actor = (Actor) this.commonDao.get(Actor.class,
                                                                         new long(78581));
            actor.getPhones().iterator;
    bon, le test est bizarre mais c'est ciblé, je sais qu'en faisant 'actor.getPhones().iterator;' je reproduis le problème donc pas besoin d'aller plus loin ;p

    Et le problème c'est, que qd je fais ça il me génère ceci comme SQL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Hibernate: select phones0_.actor_id as actor2_1_, phones0_.ID as ID1_, phones0_.ID as ID12_0_, phones0_.ACTOR_ID as ACTOR2_12_0_, phones0_.DECLARATION_ID as DECLARAT3_12_0_, phones0_.COUNTRY_CODE as COUNTRY4_12_0_, phones0_.PHONE_NUM as PHONE5_12_0_, phones0_.PHONE_CODE as PHONE6_12_0_, phones0_.START_DATE as START7_12_0_, phones0_.END_DATE as END8_12_0_ from ACTOR_PHONE phones0_ where phones0_.actor_id=?
     
     
    Hibernate: select declaratio0_.FILE_ID as ID25_0_, declaratio0_1_.FILE_TYPE_CODE as FILE2_25_0_, declaratio0_1_.INTEGRATED_FILE_ID as INTEGRATED3_25_0_, declaratio0_1_.STATUS_FCH_TYPE_CODE as STATUS4_25_0_, declaratio0_1_.START_DATE as START5_25_0_, declaratio0_1_.END_DATE as END6_25_0_, declaratio0_.DECLARATION_NUM as DECLARAT2_31_0_, declaratio0_.PROJ_TYPE_CODE as PROJ3_31_0_, declaratio0_.BUILD_START_DATE as BUILD4_31_0_, declaratio0_.BUILD_END_DATE as BUILD5_31_0_, declaratio0_.STREET_LNM as STREET6_31_0_, declaratio0_.STREET_NUM as STREET7_31_0_, declaratio0_.STREET_BOX_SHN as STREET8_31_0_, declaratio0_.POSTCODE as POSTCODE31_0_, declaratio0_.CITY_LNM as CITY10_31_0_, declaratio0_.ORDERER_PHYSICAL_IND as ORDERER11_31_0_, declaratio0_.FICTION_IND as FICTION12_31_0_, declaratio0_.REGISTER_NUM as REGISTER13_31_0_, declaratio0_.COMP_INFOS_DESC as COMP14_31_0_, declaratio0_.MOBIL_IND as MOBIL15_31_0_ from FILE_DECLARATION declaratio0_ inner join FILES declaratio0_1_ on declaratio0_.FILE_ID=declaratio0_1_.ID where declaratio0_.FILE_ID=?

    La première requête ok mais la seconde ne devrait pas être exécutée car je n'accède pas à la déclaration et que celle-ci est normalement 'proxyfiée'...!

    donc voila, si quelqu'un a un idée... :-)

    Merci

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    383
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 383
    Points : 468
    Points
    468
    Par défaut
    J'ai l'impression que le mapping que tu donnes en exemple ne correspond pas au code que tu montres.
    En fait tu navigues dans l'autre sens.
    C'est pas plutôt le mapping de la classe Actor (avec un set de Phones) qu'il faut que tu postes ?

  3. #3
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    En fait j'ai l'impression que l'erreur viend de la many-to-one car ce sont les declarations qui sont chargées quand j'accède au phone...

    sinon je peux effectivement mettre le mapping qui se trouve dans Actor:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        <set name="phones" inverse="true" cascade="all-delete-orphan">
          <key column="actor_id" />
          <one-to-many class="Phone"  />
        </set>
    Maintenant c'est peut-être la stratégie du lazy loading d'initialiser toutes les propriétés si on accède à l'objet mais je trouve ça dommage qu'il le fasse aussi pour la many-to-one, ça me coute pas mal de temps et de requêtes pour rien...

    Merci pour ton aide :-)

  4. #4
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    Uuuup ^^

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    383
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 383
    Points : 468
    Points
    468
    Par défaut
    Ben non effectivement le comportement par défaut est le lazy loading des entités et des collections.

    Par contre, ce comportement est vrai si tu charges l'instance d'Actor avec la méthode load() (dans ton DAO),
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Actor actor = (Actor) session.load(Actor.class, new long(78581))
    alors qu'aucun proxy n'est retourné si tu utilises un get()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Actor actor = (Actor) session.get(Actor.class, new long(78581))

  6. #6
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    C'est pareil avec un load/get ou une query

    Je vais devoir me résigner à faire un join pour au moins éviter les n+1 select mais c'est vraiment dommage, j'en viens à me demander s'il n'y a pas un bug au niveau Hibernate...

    Merci quand même :-)

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Juste une question en passant... par curiosité surtout...

    Par défaut, Hibernate utiliser lazy=false pour une association <many-to-one>, donc, il est normal que la requête soit exécutée

    Cependant, j'ai remarqué que tu avais 2 <many-to-one> à la suite dans le mapping de Phone, 1 pour "actor", l'autre pour "declaration".
    Dans l'extrait de la log, on voit le chargement de "declaration" mais pas de "actor" (alors qu'elles sont mappés de la même manière)
    Peut-être as-tu coupé la log... mais sinon, ça surprend...
    Comment se fait-il que dans le premier cas il ne fait pas la requête d'accès alors que dans le 2ème si...

    A+

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    383
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 383
    Points : 468
    Points
    468
    Par défaut
    Par défaut Hibernate utilise lazy=true pour les entités et les collections (à partir de la version 3).
    Pour avoir du eager (lazy=false) il faut le spécifier explicitement dans le mapping de la relation.

    D'après ce que je comprends du SQL, Actor est déjà chargé, il charge la collection de Phones quand tu accèdes à cette collection.

    Par contre, ce que moi je trouve curieux c'est qu'il n'y ait pas de jointure sur actor_Id quand il charge la Declaration.

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par slevy Voir le message
    Par défaut Hibernate utilise lazy=true pour les entités et les collections (à partir de la version 3).
    Désolé de te contredire, mais j'ai sous les yeux la version 3.2 final de la doc Hibernate et il est clairement dit qu'une relation <many-to-one> à comme valeur par défaut lazy=false
    ...
    (12) lazy (optionnel - par défaut à false) : Indique que cette propriété doit être chargée en différé (lazy
    loading) au premier accès à la variable d'instance (nécessite une instrumentation du bytecode lors de la
    phase de construction). Remarquez que cela n'influence pas le comportement du proxy Hibernate -
    comme l'attribut lazy sur des classes ou des mappings de collections, mais utilise l'interception pour le
    chargement différé. lazy="false" indique que l'association sera toujours chargée.
    ...

  10. #10
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    Shame on me

    public int hashCode() {

    if (this.actor != null && this.declaration != null && this.phoneNumber != null) {
    return (this.phoneNumber.hashCode() + this.actor.hashCode() + this.declaration.hashCode());
    } else {
    return super.hashCode();
    }
    }
    tout est dit ;-p désolé pour le dérangement ^^

    Par contre je vais devoir trouver un autre hashcode ;p

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Damned, la version 3.2.2 (en anglais) n'a pas la même valeur par défaut pour le lazy !!!
    (12) lazy (optional - defaults to proxy): By default, single point associations are proxied. lazy="no-proxy"
    specifies that the property should be fetched lazily when the instance variable is first accessed (requires
    build-time bytecode instrumentation). lazy="false" specifies that the association will always be eagerly
    fetched.
    Font ch... ces changements à la noix !

  12. #12
    Membre actif Avatar de bidi
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    262
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2004
    Messages : 262
    Points : 266
    Points
    266
    Par défaut
    En effet, mieux vaut directement lire la version en anglais ^^

    Merci à tous en tout cas

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

Discussions similaires

  1. [ lazy ] many to one
    Par hocinema dans le forum Hibernate
    Réponses: 16
    Dernier message: 28/03/2007, 21h45
  2. Hibernate : suppression sur relation many to one
    Par taf dans le forum Hibernate
    Réponses: 1
    Dernier message: 23/05/2006, 13h08
  3. [hibernate] "many-to-one"
    Par mehdi_swatch dans le forum Hibernate
    Réponses: 26
    Dernier message: 12/05/2006, 20h11
  4. [hibernate] problème pour desactiver le lazy loading
    Par agougeon dans le forum Hibernate
    Réponses: 2
    Dernier message: 14/03/2006, 11h20
  5. [HIBERNATE 3]Lazy loading
    Par SEMPERE Benjamin dans le forum Hibernate
    Réponses: 11
    Dernier message: 08/02/2006, 22h40

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