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 :

Jointure indirecte à travers plusieurs niveaux d'héritage


Sujet :

Hibernate Java

  1. #1
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut Jointure indirecte à travers plusieurs niveaux d'héritage
    Bonjour,
    Dans la BDD, j'ai la structure en héritage corespondant à ce MCD :
    Etudiant -(1,1)----Etre----0,1- Candidat -(1,1)----Etre----0,1- Utilisateur -(1,1)----Etre----0,1- Personne

    L'identifiant de la personne est aussi celui de l'utilisateur / candidat / étudiant.

    En SQL, je pourrais ainsi faire une jointure directe entre Etudiant et Personne. Mais dans le mapping généré par Seam Generate Entities, Etudiant n'est relié qu'à Candidat, qui lui même n'est relié qu'à Utilisateur, qui lui même n'est relié qu'à Personne.

    J'ai vu ailleurs qu'en HQL, join n'est pas accompagné de on puisqu'il semble que Hibernate se débrouille tout seul pour trouver les conditions de jointures.

    Comment alors puis-je faire une jointure directe entre Personne et Etudiant ?

    Voici la requête actuelle :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
                Query query = entityManager.createQuery("from ThEtudiantEtu e "
                        + "join TePersonnePrs p "
                        + "where p.prsNom = :nom "
                        + "and p.prsPrenom = :prenom " 
                        + "and e.etuDateNaissance = :dateNaissance ");
    Elle donne cette erreur :
    javax.servlet.ServletException: #{identification.identifier}: java.lang.IllegalArgumentException: org.hibernate.hql.ast.QuerySyntaxException: Path expected for join! [from org.domain.stamas.entity.ThEtudiantEtu e join TePersonnePrs p where p.prsNom = :nom and p.prsPrenom = :prenom and e.etuDateNaissance = :dateNaissance ]
    Que me conseillez-vous ?

  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
    Tu n'a pas besoin de jointure. Puisque Etudiant hérite de tout ça, tu utilise uniquement etudiant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
                Query query = entityManager.createQuery("from ThEtudiantEtu e "
                        + "where e.prsNom = :nom "
                        + "and e.prsPrenom = :prenom " 
                        + "and e.etuDateNaissance = :dateNaissance ");

  3. #3
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Maintenant j'ai cette erreur :
    javax.servlet.ServletException: #{identification.identifier}: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: prsNom of: org.domain.stamas.entity.ThEtudiantEtu [from org.domain.stamas.entity.ThEtudiantEtu e where e.prsNom = :nom and e.prsPrenom = :prenom and e.etuDateNaissance = :dateNaissance ]
    Apparemment, il ne suit pas le chemin jusqu'au bout !

  4. #4
    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
    tu peux donner ton mapping et tes classes?

  5. #5
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Mapping généré automatiquement par Seam Generate Entities des JBoss Tools dans Eclipse.

    Dans ThEtudiantEtu.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
    /**
     * ThEtudiantEtu generated by hbm2java
     */
    @Entity
    @Table(name = "th_etudiant_etu")
    public class ThEtudiantEtu implements java.io.Serializable {
    // ...
        @GenericGenerator(name = "genEtudiant", strategy = "foreign", parameters = @Parameter(name = "property", value = "thCandidatCnd"))
        @Id
        @GeneratedValue(generator = "genEtudiant")
        @Column(name = "etu_id_candidat", unique = true, nullable = false)
        public int getEtuIdCandidat() {
            return this.etuIdCandidat;
        }
     
        public void setEtuIdCandidat(int etuIdCandidat) {
            this.etuIdCandidat = etuIdCandidat;
        }
    // ...
        @OneToOne(fetch = FetchType.LAZY)
        @PrimaryKeyJoinColumn
        @NotNull
        public ThCandidatCnd getThCandidatCnd() {
            return this.thCandidatCnd;
        }
     
        public void setThCandidatCnd(ThCandidatCnd thCandidatCnd) {
            this.thCandidatCnd = thCandidatCnd;
        }
    // ...
    Dans ThCandidatCnd :
    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
    /**
     * ThCandidatCnd generated by hbm2java
     */
    @Entity
    @Table(name = "th_candidat_cnd")
    public class ThCandidatCnd implements java.io.Serializable {
    // ...
        public ThCandidatCnd(ThUtilisateurUti thUtilisateurUti) {
            this.thUtilisateurUti = thUtilisateurUti;
        }
    // ...
        @GenericGenerator(name = "genCandidat", strategy = "foreign", parameters = @Parameter(name = "property", value = "thUtilisateurUti"))
        @Id
        @GeneratedValue(generator = "genCandidat")
        @Column(name = "cnd_id_utilisateur", unique = true, nullable = false)
        public int getCndIdUtilisateur() {
            return this.cndIdUtilisateur;
        }
     
        public void setCndIdUtilisateur(int cndIdUtilisateur) {
            this.cndIdUtilisateur = cndIdUtilisateur;
        }
     
        @OneToOne(fetch = FetchType.LAZY)
        @PrimaryKeyJoinColumn
        @NotNull
        public ThUtilisateurUti getThUtilisateurUti() {
            return this.thUtilisateurUti;
        }
     
        public void setThUtilisateurUti(ThUtilisateurUti thUtilisateurUti) {
            this.thUtilisateurUti = thUtilisateurUti;
        }
    // ...
        @OneToOne(fetch = FetchType.LAZY, mappedBy = "thCandidatCnd")
        public ThEtudiantEtu getThEtudiantEtu() {
            return this.thEtudiantEtu;
        }
     
        public void setThEtudiantEtu(ThEtudiantEtu thEtudiantEtu) {
            this.thEtudiantEtu = thEtudiantEtu;
        }
    // ...
    Dans ThUtilisateurUti :
    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
    /**
     * ThUtilisateurUti generated by hbm2java
     */
    @Entity
    @Table(name = "th_utilisateur_uti")
    public class ThUtilisateurUti implements java.io.Serializable {
    // ...
        @GenericGenerator(name = "genUtilisateur", strategy = "foreign", parameters = @Parameter(name = "property", value = "tePersonnePrs"))
        @Id
        @GeneratedValue(generator = "genUtilisateur")
        @Column(name = "uti_id_personne", unique = true, nullable = false)
        public int getUtiIdPersonne() {
            return this.utiIdPersonne;
        }
     
        public void setUtiIdPersonne(int utiIdPersonne) {
            this.utiIdPersonne = utiIdPersonne;
        }
     
        @OneToOne(fetch = FetchType.LAZY)
        @PrimaryKeyJoinColumn
        @NotNull
        public TePersonnePrs getTePersonnePrs() {
            return this.tePersonnePrs;
        }
     
        public void setTePersonnePrs(TePersonnePrs tePersonnePrs) {
            this.tePersonnePrs = tePersonnePrs;
        }
    // ...
        @OneToOne(fetch = FetchType.LAZY, mappedBy = "thUtilisateurUti")
        public ThCandidatCnd getThCandidatCnd() {
            return this.thCandidatCnd;
        }
     
        public void setThCandidatCnd(ThCandidatCnd thCandidatCnd) {
            this.thCandidatCnd = thCandidatCnd;
        }
    // ...
    Dans TePersonnePrs :
    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
    /**
     * TePersonnePrs generated by hbm2java
     */
    @Entity
    @Table(name = "te_personne_prs")
    public class TePersonnePrs implements java.io.Serializable {
    // ...
        @Id
        @GeneratedValue(strategy = IDENTITY)
        @Column(name = "prs_id", unique = true, nullable = false)
        public Integer getPrsId() {
            return this.prsId;
        }
     
        public void setPrsId(Integer prsId) {
            this.prsId = prsId;
        }
    // ...
        @OneToOne(fetch = FetchType.LAZY, mappedBy = "tePersonnePrs")
        public ThUtilisateurUti getThUtilisateurUti() {
            return this.thUtilisateurUti;
        }
    // ...

  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
    Ha oui, mais il y a pas l'héritage que tu mentionnait dans le premier post là!! Faut savoir, tu veux un héritage ou pas d'héritage? Par ce que là, t'as juste un paquet de classes en relation 1-1, ce qui est pas la même chose!

  7. #7
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Comme dit plus haut, ça a été généré automatiquement par Seam Generate Entities.
    Et comme c'est une BDD MySQL, le concept clair d'héritage n'y figure pas. Mais ça a été modélisé comme un héritage de tables.

    Que faudrait-il pour faire comprendre à Hibernate qu'il y a héritage entre toutes ces tables ?

    Cette partie n'est-elle pas sensée faire ce boulot ?
    Exemple dans ThCandidatCnd :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        @OneToOne(fetch = FetchType.LAZY, mappedBy = "thCandidatCnd")
        public ThEtudiantEtu getThEtudiantEtu() {
            return this.thEtudiantEtu;
        }
     
        public void setThEtudiantEtu(ThEtudiantEtu thEtudiantEtu) {
            this.thEtudiantEtu = thEtudiantEtu;
        }

  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
    tu dois avoir un héritage au niveau de tes classes. Les outils automatique, c'est bien pour débroussailler le terrain, masi après faut mettre la main à la pate et gérer ce qui n'est pas géré automatiquement. Hibernante supporte le concept d'héritage. Dans ton cas, c'est le principe du "une table par classe avec jointure" qui est utilisé, pas un des plus simple à mettre en oeuvre mais le meilleur d'un point de vue organsiation SQL. Je ne l'ai jamais fait avec annotation, mais bon, ca doit etre faisable puisque c'est faisable via .hbm.xml :p

    Doc
    http://objetdirect.developpez.com/ar...heritage/#LI.4

    Dans ton cas, commence déjà par mettre les mots clés "extends" sur tes définitions de classes et le tag "@Inheritance" sur le parent.

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @Entity
    @Table(name = "te_personne_prs")
    @Inheritance(strategy=InheritanceType.JOINED)
    public class TePersonnePrs implements java.io.Serializable {
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @Entity
    @Table(name = "th_utilisateur_uti")
    @Inheritance(strategy=InheritanceType.JOINED)
    public class ThUtilisateurUti extends TePersonnePrs {
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @Entity
    @Table(name = "th_candidat_cnd")
    @Inheritance(strategy=InheritanceType.JOINED)
    public class ThCandidatCnd extends ThUtilisateurUti {
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    @Entity
    @Table(name = "th_etudiant_etu")
    public class ThEtudiantEtu extends  ThCandidatCnd{

    Par contre, ca nécessite que toutes les tables utilisent le même ID (l'id du candidat est aussi celui de la personne et de l'utilisateur qui lui correspondent);

    Et une fois le mapping avec véritable héritage mis en place, tu n'aura plus besoin, coté hibernate, de gérer toutes ces jointures dans les classe (les @Onetoone :p)

  9. #9
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Il a fallu aussi que je supprime les @Id des entités filles et je n'ai plus d'erreur à l'exécution.
    Merci.

  10. #10
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Un autre problème est apparu !
    Dans toutes les tables filles a été ajouté automatiquement (par Hibernate ? par Seam ?) l'identifiant prs_id de la table te_personne_prs.

    La requête générée par Hibernate dans mon Authenticator.java fait la jointure suivante :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        from
            stamas.th_utilisateur_uti thutilisat0_ 
        inner join
            stamas.te_personne_prs thutilisat0_1_ 
                on thutilisat0_.prs_id=thutilisat0_1_.prs_id
    On voit que la condition de jointure est faite avec prs_id et non pas avec uti_id_personne comme il se devrait.

    Je pense qu'il y a quelque chose à changer pour que Hibernate comprenne qu'en fait l'identifiant de la personne est déjà présent par la clé primaire de la table fille.

    Dans le mapping de th_utilisateur_uti, j'ai maintenant, après avoir commenté @Id, ceci :
    Code java : 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
        @GenericGenerator(name = "genUtilisateur", strategy = "foreign", parameters = @Parameter(name = "property", value = "tePersonnePrs"))
        //@Id
        @GeneratedValue(generator = "genUtilisateur")
        @Column(name = "uti_id_personne", unique = true, nullable = false)
        public int getUtiIdPersonne() {
            return this.utiIdPersonne;
        }
     
        public void setUtiIdPersonne(int utiIdPersonne) {
            this.utiIdPersonne = utiIdPersonne;
        }
     
        @OneToOne(fetch = FetchType.LAZY)
        @PrimaryKeyJoinColumn
        @NotNull
        public TePersonnePrs getTePersonnePrs() {
            return this.tePersonnePrs;
        }
     
        public void setTePersonnePrs(TePersonnePrs tePersonnePrs) {
            this.tePersonnePrs = tePersonnePrs;
        }

    Dans cette même table, j'ai une autre clé étrangère référencée de cette façon dans l'entité java :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        @UserRoles
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "uti_id_type_utilisateur", nullable = false)
        @NotNull
        public TeTypeUtilisateurTu getTeTypeUtilisateurTu() {
            return this.teTypeUtilisateurTu;
        }
     
        public void setTeTypeUtilisateurTu(TeTypeUtilisateurTu teTypeUtilisateurTu) {
            this.teTypeUtilisateurTu = teTypeUtilisateurTu;
        }
    Ne faudrait t-il pas que je mette un @JoinColumn sur utiIdPersonne dans le premier extrait de code ?

    Les @GenericGenerator et @GeneratedValue ne sont-il pas devenus inutiles ?

  11. #11
    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
    le problème, c'est que je n'ai jamais fait ça avec des annotation. En fichier mapping, ta structure correspond à ça:

    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
    <class name="Payment" table="PAYMENT">
     
        <id name="id" type="long" column="PAYMENT_ID">
     
            <generator class="native"/>
     
        </id>
     
        <discriminator column="PAYMENT_TYPE" type="string"/>
     
        <property name="amount" column="AMOUNT"/>
     
        ...
     
        <subclass name="CreditCardPayment" discriminator-value="CREDIT">
     
            <join table="CREDIT_PAYMENT">
     
                <key column="PAYMENT_ID"/>
     
                <property name="creditCardType" column="CCTYPE"/>
     
                ...
     
            </join>
     
        </subclass>
     
        <subclass name="CashPayment" discriminator-value="CASH">
     
            <join table="CASH_PAYMENT">
     
                <key column="PAYMENT_ID"/>
     
                ...
     
            </join>
     
        </subclass>
     
        <subclass name="ChequePayment" discriminator-value="CHEQUE">
     
            <join table="CHEQUE_PAYMENT" fetch="select">
     
                <key column="PAYMENT_ID"/>
     
                ...
     
            </join>
     
        </subclass>
     
    </class>
    D'après la doc, l'annotation que tu cherche, a mettre sur l'enfant, est
    @PrimaryKeyJoinColumn(name="uti_id_personne") Voir ici http://docs.jboss.org/hibernate/anno...ingle/#d0e1168 section 2.2.4.3

  12. #12
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 957
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 957
    Points : 4 386
    Points
    4 386
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    D'après la doc, l'annotation que tu cherche, a mettre sur l'enfant, est
    @PrimaryKeyJoinColumn(name="uti_id_personne") Voir ici http://docs.jboss.org/hibernate/anno...ingle/#d0e1168 section 2.2.4.3
    NB

    Pour régler certains conflits de nom de FK avec certains SGBD (de mémoire ORACLE…), vous aurez parfois aussi besoin de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    @ForeignKey(name = "UNIQUE_FK_NAME")
    sur les classes filles elles-mêmes pour spécifier un nom unique pour la FK entre PKs.

  13. #13
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Je progresse mais ce n'est pas encore ça...

    Dans ThUtilisateurUti, j'ai maintenant ceci :
    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
    @Entity
    @Table(name = "th_utilisateur_uti")
    @Inheritance(strategy=InheritanceType.JOINED)
    @PrimaryKeyJoinColumn(name = "uti_id_personne", referencedColumnName = "prs_id")
    public class ThUtilisateurUti extends TePersonnePrs implements java.io.Serializable {
    //...
        @GenericGenerator(name = "genUtilisateur", strategy = "foreign", parameters = @Parameter(name = "property", value = "tePersonnePrs"))
        //@Id
        @GeneratedValue(generator = "genUtilisateur")
        //@Column(name = "uti_id_personne", unique = true, nullable = false)
     
        public int getUtiIdPersonne() {
            return this.utiIdPersonne;
        }
     
        public void setUtiIdPersonne(int utiIdPersonne) {
            this.utiIdPersonne = utiIdPersonne;
        }
     
        @OneToOne(fetch = FetchType.LAZY)
        //@PrimaryKeyJoinColumn(name = "uti_id_personne")
        @NotNull
        public TePersonnePrs getTePersonnePrs() {
            return this.tePersonnePrs;
        }
     
        public void setTePersonnePrs(TePersonnePrs tePersonnePrs) {
            this.tePersonnePrs = tePersonnePrs;
        }
    // ...
    Comme on peut le voir, j'ai essayé de mettre l'annotation @PrimaryKeyJoinColumn à différents endroits et de diverses façons. À l'origine, généré automatiquement par Seam Generate Entites, cette annotation figurait à la dernière position ci-dessus, sans le paramètre name.

    J'ai aussi ajouté la partie SELECT dans la requête de mon authenticator.java pour éviter les multiples jointures inutiles.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
                Query query = entityManager.createQuery("SELECT utiIdPersonne "
                        + "FROM ThUtilisateurUti "
                        + "WHERE utiLogin = :username "
                        + "and utiMotPasse = :password");
                query.setParameter("username", credentials.getUsername());
                query.setParameter("password", ThUtilisateurUti.generateMD5(credentials.getPassword()));
    Avec ce code, Hibernate génère quand même une jointure avec te_personne_prs qui ne sert à rien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        select
            thutilisat0_.utiIdPersonne as col_0_0_ 
        from
            stamas.th_utilisateur_uti thutilisat0_ 
        inner join
            stamas.te_personne_prs thutilisat0_1_ 
                on thutilisat0_.uti_id_personne=thutilisat0_1_.prs_id 
        where
            thutilisat0_.uti_login=? 
            and thutilisat0_.uti_mot_passe=? limit ?
    À la limite, je m'en fout mais il continue aussi à me générer automatiquement des colonnes inutiles dans ma BDD. Par exemple dans la table th_utilisateur_uti :
    utiIdPersonne
    tePersonnePrs_prs_id
    Le programme fonctionne avec ces colonnes mais si je les supprime, l'appli plante :
    15:12:51,724 WARN [JDBCExceptionReporter] SQL Error: 1054, SQLState: 42S22
    15:12:51,724 ERROR [JDBCExceptionReporter] Unknown column 'thutilisat0_.utiIdPersonne' in 'field list'
    15:12:51,726 DEBUG [EntityTransaction] marking JPA resource-local transaction for rollback
    15:12:51,727 WARN [SeamLoginModule] Error invoking login method
    javax.el.ELException: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
    ...
    Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
    ...
    Caused by: org.hibernate.exception.SQLGrammarException: could not execute query
    ...
    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'thutilisat0_.utiIdPersonne' in 'field list'
    ...
    15:12:51,730 DEBUG [Identity] Login failed for: plemenager
    javax.security.auth.login.LoginException: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute query
    Je ne comprends pas pourquoi il crée des colonnes tout seul (j'aimerais d'ailleurs bien le lui interdire, comment fait-on ?) ni pourquoi il a besoin de ces colonnes qui sont redondantes avec l'identifiant existant et en plus elles sont vides !

    Citation Envoyé par JeitEmgie
    NB

    Pour régler certains conflits de nom de FK avec certains SGBD (de mémoire ORACLE…), vous aurez parfois aussi besoin de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @ForeignKey(name = "UNIQUE_FK_NAME")
    sur les classes filles elles-mêmes pour spécifier un nom unique pour la FK entre PKs.
    Est-ce que mon problème serait dû à ça ? Je n'ai justement pas le même nom pour les colonnes clés étrangères et les colonnes de référence (prs_id => uti_id_personne => cnd_id_utilisateur => etu_id_candidat).

    Où faudrait-il que je mette cette annotation ?

  14. #14
    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
    Unknown column 'thutilisat0_.utiIdPersonne' in 'field list'

    ce nom de colonne proviens de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        public int getUtiIdPersonne() {
            return this.utiIdPersonne;
        }
     
        public void setUtiIdPersonne(int utiIdPersonne) {
            this.utiIdPersonne = utiIdPersonne;
        }
    c'est le nom du champ. Comem tu lui dit pas quoi faire de ce getter / setter, il applique le comportement par défaut: le mapper sous son nom d'attribut.

    Retire ces getter/setters qui ne te servent plus à rien Ou, si tu veux les garder mais pas les mapper, ajoute @Transient dessus.

  15. #15
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 957
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 957
    Points : 4 386
    Points
    4 386
    Par défaut
    Citation Envoyé par CinePhil Voir le message

    Est-ce que mon problème serait dû à ça ? Je n'ai justement pas le même nom pour les colonnes clés étrangères et les colonnes de référence (prs_id => uti_id_personne => cnd_id_utilisateur => etu_id_candidat).

    Où faudrait-il que je mette cette annotation ?
    non ce problème ne se pose qu'avec certains SGBDs dans la phase de génération/création du schéma et pas à l'exécution mais c'est une habitude de bonne pratique de l'utiliser : çà permet aussi d'avoir des noms de FK "lisibles" au lieu des noms générés… (question de goût…)
    et comme dit dans mon post plus haut cette annotation se met sur la classe fille.

    quant à vos champs ajoutés et non désirés : ils sont certainement dû à vos @OneToOne en trop car une fois la liaison faite par héritage vous n'en avez plus besoin (à moins qu'ils n'expriment autre chose de fonctionnel que la relation d'héritage…)

  16. #16
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Effectivement, il a fallu que je fasse les deux manip et ça semble fonctionner correctement sans ajouter de colonnes dans ma BDD.

    Merci à vous deux.

  17. #17
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    C'était trop beau pour que ça fonctionne sans problème !

    Ne trouvant pas la méthode pour enchaîner deux requêtes SELECT, j'essaie de faire en une seule requête ce que j'aurais voulu faire en deux.

    Rappel et complément du MCD :
    Etudiant -(1,1)----Etre----0,1- Candidat -(1,1)----Etre----0,1- Utilisateur -(1,1)----Etre----0,1- Personne

    Stage -(1,1)----Etre----1,1- Session -0,n----Inscrire----0,n- Candidat

    Parmi les utilisateurs (ThUtilisateurUti), certains sont des étudiants (ThEtudiantEtu), donc des candidats (ThCandidatCnd), qui peuvent s'inscrire à une session (TeSessionSsn) de stage (ThStageStg).

    La raison pour laquelle on passe par candidat et par session au lieu d'associer directement étudiant à stage est que l'on souhaite généraliser cette partie d'inscription à quelque chose pour la réutiliser dans de futures applications.

    Je cherche donc à vérifier, lors de l'authentification, si l'étudiant est déjà inscrit à un stage, pour changer sa page d'accueil et lui redonner les informations sur son stage.
    La requête SQL suivante fonctionne :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT ssn.ssn_libelle, ssn.ssn_date_debut, ssn.ssn_date_fin,
        e.etb_nom, c.cmn_nom, d.dpt_numero
    FROM th_utilisateur_uti AS u
    LEFT OUTER JOIN th_candidat_cnd AS cnd ON cnd.cnd_id_utilisateur = u.uti_id_personne
        LEFT OUTER JOIN tj_cnd_inscrire_ssn_cis AS cis ON cis_id_candidat = cnd.cnd_id_utilisateur
            LEFT OUTER JOIN te_session_ssn AS ssn ON ssn.ssn_id = cis.cis_id_session
                LEFT OUTER JOIN th_stage_stg AS stg ON stg.stg_id_session = ssn.ssn_id
                    LEFT OUTER JOIN te_etablissement_etb AS e ON e.etb_id = stg.stg_id_etablissement
                        LEFT OUTER JOIN tr_commune_cmn AS c ON c.cmn_id = e.etb_id_commune
                            LEFT OUTER JOIN tr_departement_dpt AS d ON d.dpt_id = c.cmn_id_departement
    WHERE u.uti_login = 'etutest'

    Lorsque je ne cherche que l'utilisateur, sans le stage, ça fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Query query = entityManager.createQuery(
                        "FROM ThUtilisateurUti u " +
                        "WHERE u.utiLogin = :username " +
                            "AND u.utiMotPasse = :password");
    Dès que je veux faire la première jointure vers thCandidatCnd, ça coince !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Query query = entityManager.createQuery(
                        "FROM ThUtilisateurUti u " +
                        "JOIN u.ThCandidatCnd c " +/*
                            "LEFT JOIN c.TeSessionSsn s " +
                                "LEFT JOIN s.ThStageStg stg " +*/
                        "WHERE u.utiLogin = :username " +
                            "AND u.utiMotPasse = :password");
    Erreur obtenue :
    javax.el.ELException: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: ThCandidatCnd of: org.domain.stamas.entity.ThUtilisateurUti [FROM org.domain.stamas.entity.ThUtilisateurUti u JOIN u.ThCandidatCnd c WHERE u.utiLogin = :username AND u.utiMotPasse = :password]
    Je me suis dit que c'était parce que j'avais commenté les getters et setters et j'ai essayé diverses choses, dont ce qui suit, à partir de l'indication trouvée ici.

    Dans ThUtilisateurUti.java :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        @Transient
        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumn(name="cnd_id_utilisateur", referencedColumnName="uti_id_personne")
        public ThCandidatCnd getThCandidatCnd() {
            return this.thCandidatCnd;
        }
     
        public void setThCandidatCnd(ThCandidatCnd thCandidatCnd) {
            this.thCandidatCnd = thCandidatCnd;
        }
    Dans ThCandidatCnd par contre, j'ai laissé les getters et setters de thUtilisateurUti commentés puisqu'il y a maintenant un héritage de classes.

    En gros, le problème est que je ne peux pas descendre les niveaux d'héritage de tables dans une requête alors que la remontée se fait très bien.

  18. #18
    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
    les candidats sont des utilisateurs si j'ai bien compris?

    Alors la requete est bêtement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Query query = entityManager.createQuery(
                        "FROM ThCandidatCnd c " +
                        "WHERE c.utiLogin = :username " +
                            "AND c.utiMotPasse = :password");

  19. #19
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 801
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 801
    Points : 34 063
    Points
    34 063
    Billets dans le blog
    14
    Par défaut
    Non parce que tous les utilisateurs ne sont pas des candidats ! Je dois donc faire une jointure externe de thUtilisateurUti vers thCandidatCnd.

    A moins que tu me dises comment enchaîner deux requêtes, le processus que j'avais imaginé au départ étant que selon le résultat de la requête vérifiant le login de l'utilisateur, si celui-ci est un étudiant, alors on lance la deuxième requête permettant de savoir s'il est déjà inscrit à un stage. L'enchaînement de requêtes est l'objet de l'autre discussion dont j'ai donné de lien dans mon précédent message.

  20. #20
    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
    tu a besoin de candidat ou d'utilisateurs? J'ai pas trop compris ton but?

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

Discussions similaires

  1. Héritage sur plusieurs niveaux de user control
    Par lila23 dans le forum Silverlight
    Réponses: 6
    Dernier message: 14/09/2011, 15h18
  2. Réponses: 0
    Dernier message: 28/11/2009, 18h18
  3. [Framework] AOP - Héritage à plusieurs niveaux
    Par teletexte dans le forum Spring
    Réponses: 0
    Dernier message: 18/02/2009, 17h02
  4. Réponses: 10
    Dernier message: 25/01/2008, 16h24
  5. [Hibernate] Héritage sur plusieurs niveaux
    Par srvremi dans le forum Hibernate
    Réponses: 2
    Dernier message: 31/05/2006, 18h39

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