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 : Probleme de mapping pour une map avec une table d'association


Sujet :

Hibernate Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 13
    Points : 11
    Points
    11
    Par défaut Hibernate : Probleme de mapping pour une map avec une table d'association
    Bonjour à tous,

    je suis débutant en Hibernate et je me heurte à un problème depuis plusieurs jours. Le principe est pourtant relativement simple :

    j'ai une table User et une table Collection liées par une table d'association AssocUserCollection.

    Script SQL de création de ces tables :

    Code sql : 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
    CREATE TABLE  user (
      User_id int(10) NOT NULL auto_increment,
      User_login varchar(45) NOT NULL,
      User_password varchar(45) NOT NULL,
      PRIMARY KEY  (User_id),
    );
     
    CREATE TABLE collection (
    Collection_id int(10) NOT NULL auto_increment, 
    Collection_name varchar(45) NOT NULL,
    PRIMARY KEY (Collection_id),
    );
     
    CREATE TABLE assoccollectionuser (
    Collection_id int(10) NOT NULL, 
    User_id int(10) NOT NULL, 
    PRIMARY KEY (User_id,Collection_id),
    CONSTRAINT FK_Collection FOREIGN KEY (Collection_id) REFERENCES collection (Collection_id),
    CONSTRAINT FK_User FOREIGN KEY (User_id) REFERENCES user (User_id) 
    );

    Mon problème est le suivant :

    Je voudrais que ma classe User (mappée à la table du même nom) contienne une Map<String, Collection> avec en clé le nom de la collection (collection_name).

    J'ai donc essayé ça :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <map name="collections" table="assocCollectionUser">
            <key column="user_id" />
            <map-key type="string" column="collection_name"></map-key>
            <many-to-many column="collection_id" class="Collection"/> 
    </map>

    Le problème c'est qu'Hibernate cherche dans la table d'association et non dans la table Collection la colonne 'collection_name', et donc forcément ça plante.
    Y a-t-il un moyen de résoudre ce problème ?

    PS : j'ai réussi à trouver une solution relativement moche en mettant :
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ...
    <map-key type="string" column="collection1_1_.collection_name"></map-key>
    ...

    collection1_1_ étant l'alias de la table collection utilisé par Hibernate d'après la requête SQL que j'ai récupérée.

  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
    Pourquoi cherches-tu absolument à mapper sur le collection_name ?

    Mappe avec le collection_id à la place :
    <map-key type="string" column="collection_id"></map-key>

    A partir de ce moment Hibernate comprend le type d'association de ton modèle.

    Tu spécifieras le collection_name dans la requête.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    Merci slevy pour cette réponse rapide.

    Effectivement je peux modifier la façon dont je récupère ma collection, mais le but serait d'avoir une Map pour avoir simplement à faire "user.getCollections.get('nomDeLaCollection')" pour récupérer la collection souhaitée sans repasser par une requête plus où moins manuelle.

    En fait pour le moment j'ai déjà réussi à contourner le problème (plus ou moins joliment) et j'aimerais savoir s'il est possible d'avoir l'implémentation que je souhaite ou si Hibernate ne le permet pas.

  4. #4
    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
    Tu as essayé de mapper comme ça ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     
    <map name="collections" table="assocCollectionUser">
       <key column="user_id" />
       <map-key-many-to-many type="string" column="collection_name" class="Collection" />
       <many-to-many column="collection_id" class="Collection"/> 
    </map>

  5. #5
    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
    y a moyen d'utiliser le retour d'une requete hql comme clé, l'ennui c'est que çà rend la map read-only. Et puis faut garder la cohérence.

    si t'as comme map <String,Collection>, qu'est supposé faire hibernate si tu place dedans un put("test",collectionQuiAPourNameAutchoz) et que tu veux persister?

    Le mieux est peut etre encore d'avoir un mapping hibernate "privéé" et ensuite des méthode publiques, non utilisées par hibernate, qui utilisent se mapping privé pour le présenter autrement à l'utilisateur. Après tout, Map est un interface, tu est libre de l'implémenter toi meme....

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    Merci pour vos réponses.

    Slevy, j'ai essayé avec ton code mais ça ne marche pas;apparemment la balise <map-key-many-to-many> sert à mapper des entity et non des types simples.

    Mais en fait je pense que mon implémentation est impossible car cela revient à mapper une classe à partir de deux tables différentes (d'après ce que j'ai lu c'est quand même possible avec Hibernate mais à éviter).

    tchize_ si tu as deux minutes est-ce que tu pourrais détailler un peu ce que tu entends par :

    Le mieux est peut etre encore d'avoir un mapping hibernate "privéé" et ensuite des méthode publiques, non utilisées par hibernate, qui utilisent se mapping privé pour le présenter autrement à l'utilisateur
    Je mettrai ma question en RÉSOLU (ben oui, savoir qu'il n'y a pas de solution c'est déjà une solution) en fin de semaine, si tu ne m'as pas répondu je considèrerai que tu n'as pas eu le temps.

    Merci

  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
    hibernate travaille par reflection / proxy / injection sur des getters/setter. Rien n'oblige que ces getters / setters soient publics. Tu peux donc créer des propriétés, mappée par hibernate, qui sont protected. Par exemple une collection telle que la voit hibernate. Une fois cela fait, tu peux toujours créer des propriétés dérivées, hibernate s'ne fout, il les gère pas, t'en fait ce que tu veux. Exemple, à partir d'un List<Entite> qui viens d'hibernate (appelons le collectionPrivate), tu peux créer une propriété dériver Map<String,entité> qui serait publique, appelée maCollection et dont les données viennent de collectionPrivate. Shématiquement on aurait

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public Map getMaCollection(){
        HashMap map = new HashMap();
        pour chaque entrée dans getCollectionPrivate() faire 
            map.put(Entite.getName(),Entite);
        return map;
    }

  8. #8
    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
    Si çà peut te servir, voilà un mapping tordu qu'on a du faire au boulot.

    Les tables:
    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
     
    CREATE TABLE "RH_EMPLOYEE" ......
     
     
     CREATE TABLE "RH_EMP_FCT_GROUP_LINK" 
       (	"LINK_ID" NUMBER(10,0), 
    	"EMP_ID" NUMBER(10,0), 
    	"FCT_GROUP_ID" NUMBER(10,0), 
    	"FCT_ID" NUMBER(10,0), 
    	 CONSTRAINT "PK_RH_EMP_FCT_GROUP_LINK" PRIMARY KEY ("LINK_ID")
      )
     
      CREATE TABLE "RH_EMP_FCT_GROUP" 
       (	"FCT_GROUP_ID" NUMBER(10,0) NOT NULL ENABLE, 
    	"FCT_GROUP_KEY" VARCHAR2(255) NOT NULL ENABLE, 
    	"FCT_GROUP_NAME_FR" VARCHAR2(255), 
    	"FCT_GROUP_NAME_NL" VARCHAR2(255), 
    	 CONSTRAINT "PK_RH_EMP_FCT_GROUP" PRIMARY KEY ("FCT_GROUP_ID")
      )
     
    CREATE TABLE "RH_EMP_FUNCTION" 
       (	"FCT_ID" NUMBER(10,0) NOT NULL ENABLE, 
    	"FCT_KEY" VARCHAR2(255 BYTE) NOT NULL ENABLE, 
    	"FCT_NAME_FR" VARCHAR2(255 BYTE), 
    	"FCT_NAME_NL" VARCHAR2(255 BYTE), 
    	"MANAGER" NUMBER(10,0), 
    	 CONSTRAINT "PK_RH_EMP_FUNCTION" PRIMARY KEY ("FCT_ID"))
    Le mapping de propriétés dans Employéé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    		<map name="privateManagers" table="RH_EMP_FCT_GROUP_LINK">
    		    <key column="EMP_ID"/>
    		    <map-key formula="(select grp.FCT_GROUP_KEY from RH_EMP_FCT_GROUP grp where grp.FCT_GROUP_ID=FCT_GROUP_ID)" type="string"/>
    		    <many-to-many column="FCT_ID" class="be.rmi.intranet.db.users.Function" />
    		</map>
     
    		<map name="functionGroups" table="RH_EMP_FCT_GROUP_LINK">
    		    <key column="EMP_ID"/>
    		    <map-key-many-to-many column="FCT_GROUP_ID" class="be.rmi.intranet.db.users.FunctionGroup"/>
    		    <many-to-many column="FCT_ID" class="be.rmi.intranet.db.users.Function"/>
    		</map>
    Tu notera que la table de lien lie un employé + un function group à un function. Cette table permet de faire des chose du style "la <secrétaire> de <monsieur dupont> est <madame dupond>". Le deuxième mapping permet de récupérer un FUNCTION en utilisant un FUNCTION_GROUP comme clé. Le premier permet de faire la meme chose sauf que la clé est le "key" du function group et non le functiongroup en lui meme. çà permet de faire des choses genre employee.getPrivateManagers().get("secretary");, ce qui est plus pratique dans un cadre jsf :p
    L'ennui du formula: c'est du read-only et si je change la map 'functionGroups', ma map privateManager sera désynchro.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2008
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    Merci beaucoup pour tes réponses tchize_.

    Je vais me pencher sur la question des attributs privés/publics.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 13/04/2015, 12h17
  2. Mapper l'attribut name d'une checkbox avec une map
    Par FooFighters dans le forum Struts 2
    Réponses: 0
    Dernier message: 03/01/2015, 22h47
  3. [XL-2002] Macro de comparaison d'une cellule d'une feuille avec une cellule d'une autre feuille.
    Par steelydan dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 08/09/2010, 13h59
  4. Réponses: 4
    Dernier message: 15/10/2009, 14h33
  5. Réponses: 3
    Dernier message: 06/11/2007, 12h18

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