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

JPA Java Discussion :

Clé composite comme nouvel ID


Sujet :

JPA Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mars 2007
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 25
    Par défaut Clé composite comme nouvel ID
    Bonjour à tous,

    Voila, depuis quelque temps je me casse la tête sur un problème .
    Le mieux étant de vous montrer un code épuré.

    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
     
    @Entity
    public class A implements Serializable {
     
    	@Id
            @JoinColumn(name="c1")
    	private String c1;
     
            ...
    }
     
    @Entity
    public class B implements Serializable {
     
    	@Id
            @JoinColumn(name="c3")
    	private String c3;
     
    	@Id
            @JoinColumn(name="c4")
    	private String c4;
     
            ...
    }
    Jusque la tout va bien. Je voudrais maintenant la classe C suivante :

    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
     
    @Entity
    public class C implements Serializable {
     
    	@Id
            @JoinColumn(name="c5")
    	private A c5;
     
    	@Id
    	@JoinColumns({
                @JoinColumn(name="c6", referencedColumnName="c3"),
                @JoinColumn(name="c7", referencedColumnName="c4")
    	})
    	private B c6;
     
            ...
    }
    En écrivant ce code j'ai les logs suivants

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    cannot Deploy CalinfoERP
    Deployment Error for module: CalinfoERP: Exception while preparing the app : org.glassfish.deployment.common.DeploymentException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.EntityManagerSetupException
    Exception Description: Predeployment of PersistenceUnit [EJB] failed.
    Internal Exception: java.lang.ClassCastException: org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.IdAccessor cannot be cast to org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor
    Exception while invoking class org.glassfish.persistence.jpa.JPADeployer prepare method : javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.EntityManagerSetupException
    Exception Description: Predeployment of PersistenceUnit [EJB] failed.
    Internal Exception: java.lang.ClassCastException: org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.IdAccessor cannot be cast to org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor
    Si je retire le @Id sur c6, ca fonctionne correctement, seulement voila, les clés primaires ne sont pas correctes. De plus, je suis obligé d'avoir cette classe pour pouvoir avoir les méthodes getC5 et getC6.

    Quelqu'un aurait il une solution ?

    Thank's

  2. #2
    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
    Billets dans le blog
    1
    Par défaut
    Que je sache, on ne peut pas mettre plusieurs @ID dans un entity, lorqu'on utilise des clés composites, on passe par une classe additionnelle représentant les champs de la clé et c'est cette classe qui sera référencée dans l'entity.
    Un exemple pour illustrer :
    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
     
    package com.obia.ejb.client.entity;
     
    import java.io.Serializable;
    import javax.persistence.*;
     
     
    /**
     * The persistent class for the bike_owner database table.
     * 
     */
    @Entity
    @Table(name="bike_owner")
    public class BikeOwner implements Serializable {
        private static final long serialVersionUID = 1L;
        private BikeOwnerPK id;
        private Bike bike;
        private Owner owner;
     
        public BikeOwner() {
        }
     
     
        @EmbeddedId
        public BikeOwnerPK getId() {
            return this.id;
        }
     
        public void setId(BikeOwnerPK id) {
            this.id = id;
        }
     
     
        //bi-directional many-to-one association to Bike
        @ManyToOne
        @JoinColumn(name="uid_bike", insertable=false, updatable=false)
        public Bike getBike() {
            return this.bike;
        }
     
        public void setBike(Bike bike) {
            this.bike = bike;
        }
     
     
        //bi-directional many-to-one association to Owner
        @ManyToOne
        @JoinColumn(name="uid_owner", insertable=false, updatable=false)
        public Owner getOwner() {
            return this.owner;
        }
     
        public void setOwner(Owner owner) {
            this.owner = owner;
        }   
    }
    et la clé
    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
     
    package com.obia.ejb.client.entity;
     
    import java.io.Serializable;
    import javax.persistence.*;
     
    /**
     * The primary key class for the bike_owner database table.
     * 
     */
    @Embeddable
    public class BikeOwnerPK implements Serializable {
        //default serial version id, required for serializable classes.
        private static final long serialVersionUID = 1L;
        private int uidOwner;
        private int uidBike;
     
        public BikeOwnerPK() {
        }
     
        @Column(name="uid_owner")
        public int getUidOwner() {
            return this.uidOwner;
        }
        public void setUidOwner(int uidOwner) {
            this.uidOwner = uidOwner;
        }
     
        @Column(name="uid_bike")
        public int getUidBike() {
            return this.uidBike;
        }
        public void setUidBike(int uidBike) {
            this.uidBike = uidBike;
        }
     
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (!(other instanceof BikeOwnerPK)) {
                return false;
            }
            BikeOwnerPK castOther = (BikeOwnerPK)other;
            return 
                (this.uidOwner == castOther.uidOwner)
                && (this.uidBike == castOther.uidBike);
     
        }
     
        public int hashCode() {
            final int prime = 31;
            int hash = 17;
            hash = hash * prime + this.uidOwner;
            hash = hash * prime + this.uidBike;
     
            return hash;
        }
    }
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 963
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 963
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Que je sache, on ne peut pas mettre plusieurs @ID dans un entity, lorqu'on utilise des clés composites, on passe par une classe additionnelle représentant les champs de la clé et c'est cette classe qui sera référencée dans l'entity.
    Si, on peut.

    Il y aura aussi une classe pour la PK que l'on spécifiera avec @IdClass sur l'entité.

  4. #4
    Membre averti
    Inscrit en
    Mars 2007
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 25
    Par défaut
    Re salut

    Oui, on peut ajouter plusieurs @ID dans la même classe.

    Mais j'aurais pu écrire la classe B comme 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
     
     
    @Embeddable
    public class BPK implements Serializable {
     
            @JoinColumn(name="c3")
    	private String c3;
     
            @JoinColumn(name="c4")
    	private String c4;
     
            ...
    }
     
    @Entity
    public class B implements Serializable {
     
    	@EmbeddedId
    	private BPK c7;
     
            ...
    }
    Ceci étant ça ne répond pas à mon problème pour la classe C.

    Comment avoir en ID dans la class C, les ID de la class B et l'ID de la class A tout en ayant la possibilité d'avoir sur la class C les méthodes les méthodes getC5 et getC6.


  5. #5
    Membre averti
    Inscrit en
    Mars 2007
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 25
    Par défaut
    Re salut,

    En faite je me suis un peux trompé dans mon exemple (celui indiqué dans le premier poste marche correctement). Donc, on oublie ce qu'il y a ci-dessus, et je reprend depuis le début.

    Voici mon pbm

    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
     
    @Entity
    public class A implements Serializable {
     
    	@Id
            @JoinColumn(name="a1")
    	private String a1;
     
            ...
    }
     
    @Entity
    public class B implements Serializable {
     
    	@Id
            @JoinColumn(name="b1")
    	private String b1;
     
    	@Id
            @JoinColumn(name="b2")
            @ManyToOne
    	private A b2;
     
            ...
    }
    Jusque la tout va bien,

    je veux maintenant la class C suivante
    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
     
    @Entity
    public class C implements Serializable {
     
    	@Id          //Si je retire ce @Id, ca fonctionne correctement
    	@JoinColumns({
                @JoinColumn(name="c1", referencedColumnName="b1"),
                @JoinColumn(name="c1", referencedColumnName="b2")
    	})
            @ManyToOne
    	private B c3;
     
    	@Id
            @JoinColumn(name="c4")
    	private String c4;
     
            ...
    }
    Evidemment il me faut tj dans la classe C les méthode getC3 et getC4. Toutefois, il faut que la table C générée en base est les ID c4, c1 et c2. Mais ca ne fonctionne pas.

    Si je retire le @Id sur c3, j'ai la table qu'il me faut, mais évidemment, c1 et c2 ne sont pas des clef primaire. Il n'y a que c4 en clef primaire. Donc ca ne me va pas.

    Please Help.


  6. #6
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 963
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 963
    Par défaut
    a. @JoinColumn est une annotation pour spécifier une colonne dans la jointure d'une entité : elle n'a rien à faire sur un type primitif

    b. plusieurs @Id demande que l'on spécifie la classe qui gérera le tout par @IdClass sur l'entité, ce que vous n'avez toujours pas fait

    Exemple repris de PRO-JPA2 (APress) qui montre l'usage conjoint des 2 méthodes (@IdClass et @EmbeddedId):

    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
     
    @Entity
    @IdClass(ProjectId.class)
    public class Project {
    @Id private String name ;
    @Id 
    @ManyToOne
    private Department dept;
    …
    }
     
    public class ProjectId implements Serializable {
    private String name ;
    private DeptId dept;
     
    public ProjectId() {}
    public ProjectId(DeptId deptId, String name) {}}
     
    @Entity 
    public class Department {
    @EmbeddedId private DeptId id ;
    …
    }

  7. #7
    Membre averti
    Inscrit en
    Mars 2007
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 25
    Par défaut
    Merci à tous pr ce pbm,

    a. @JoinColumn est une annotation pour spécifier une colonne dans la jointure d'une entité : elle n'a rien à faire sur un type primitif
    Oui effectivement, c'est une faute de frappe

    b. plusieurs @Id demande que l'on spécifie la classe qui gérera le tout par @IdClass sur l'entité, ce que vous n'avez toujours pas fait
    D'après ce site http://docs.jboss.org/hibernate/core...declaration-id qui est pas mal du tout, en recherchant la ligne "As you can see the last case is far from obvious.", il explique visiblement que la façons de faire avec IdClass est déprécié et que si ça existe, c'est pour assurer la compatibilité avec EJB2.

    Pour mon problème, en cherchant (ou plutôt lisant) sur ce même site (cf ci-dessus), le point 5.1.2.1.2 m'indique que ce que je veux faire n'est pas compatible avec le standard JPA mais est compatible avec hibernate. j'ai donc changer mon provider "oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider" par "org.hibernate.ejb.HibernatePersistence". Et la, ta daaaa, ça marche.

    Bon ça c'est cool. Parcontre qu'elque chose qui marchait avant avec JPA ne marche maintenant plus avec Hibernate. Donc voici mon nouveau pbm (plus simple à expliquer)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    @Entity
    @Table(name = "erp_table")
    public class TableObject implements Serializable {
     
    	@Id
    	@Column(name = "name")
    	private String name;
     
    	...
    }
    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
     
    @Entity
    @Table(name = "erp_table_role_access")
    public class TableRoleAccess implements Serializable {
     
    	@Id
    	@JoinColumn(name = "table_name")
    	@ManyToOne(fetch = FetchType.EAGER)
    	private TableObject table;
     
    	@Id                    //En retirant cette anotation, ça fonctionne
    	@JoinColumn(name = "role")
    	@ManyToOne(fetch = FetchType.EAGER)
    	private ErpRole role;
     
    	...
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    @Entity
    @Table(name = "erp_role")
    public class ErpRole implements Serializable {
     
    	@Id
    	@Column(name = "role")
    	private String role;
     
    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "role", cascade = CascadeType.ALL)
    	private List<TableRoleAccess> tableAccessList = new ArrayList<TableRoleAccess>();
     
    	...
    }
    En retirant l'anotation @Id (comme indiqué dans le code) ça fonctionne, mais évidement l'id n'est plus correcte.

    L'erreur émise est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    cannot Deploy TestERP
    Deployment Error for module: TestERP: Exception while preparing the app : org.glassfish.deployment.common.DeploymentException: mappedBy reference an unknown target entity property: erp.bdd.shm.TableRoleAccess.role in erp.bdd.shm.ErpRole.tableAccessList
    Exception while invoking class org.glassfish.persistence.jpa.JPADeployer prepare method : org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: erp.bdd.shm.TableRoleAccess.role in erp.bdd.shm.ErpRole.tableAccessList
    Cette erreur indique que la propriété role n'existe pas dans la classe TableRoleAccess. Pourtant si, elle y est bien.

    Du coup je tombe de nouveau sur un nouvel echec. Mais un poil différent de l'autre ce coup si.

  8. #8
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 963
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 963
    Par défaut
    C'est l'un OU l'autre…

    Si vous ne voulez pas de @IdClass alors utilisez partout @EmbeddedId, mais n'essayez pas des mélanges qui ne sont pas supportés.

    De plus il est fondamental de bien spécifier si vous travaillez en JPA 1.0 ou 2.0 : les solutions ne sont pas identiques.

    En JPA 1.0, il faudra ajouter des "insertable=false" sur certaines @Column.

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

Discussions similaires

  1. Enregistrer procédure comme nouvelle fonction
    Par guinotfr dans le forum Maple
    Réponses: 0
    Dernier message: 21/12/2010, 10h11
  2. Nouvel extension a traiter comme du PHP
    Par Invité dans le forum Apache
    Réponses: 1
    Dernier message: 17/04/2007, 17h16
  3. [FEDORA] basculer comme nouvel User
    Par zsoh dans le forum RedHat / CentOS / Fedora
    Réponses: 3
    Dernier message: 06/03/2007, 16h04
  4. Insert avc comme variable le nouvel id cree
    Par escafr dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 09/11/2005, 19h32

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