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 :

Persist ManyToMany - duplicate entry ou detached entity


Sujet :

JPA Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut Persist ManyToMany - duplicate entry ou detached entity
    Bonjour,

    J'essaye de faire persister mon entité qui possède une relation ManyToMany en base. Malheureusement je rencontre quelques souci.

    Déjà voici les entitées :
    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
    @Entity
    @Table(name = "USER")
    public class User implements Serializable {
     
        private static final long serialVersionUID = 1L;
     
        @Id
        @Column(name = "ID")
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long userId;
     
        @Column(name = "NAME", unique = true, nullable = false)
        String userName;
     
        @Column(name = "FORNAME")
        String userForname;
     
        @Column(name = "EMAIL")
        String userEmail;
     
        @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        @JoinTable(name = "USER_USER_ROLES", joinColumns = @JoinColumn(name = "ID_USER"), inverseJoinColumns = @JoinColumn(name = "ID_ROLE"))
        List<UserRoles> userRoles = new ArrayList<UserRoles>();
     
        // getter et setter
    }
    et
    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
    @Entity
    @Table(name = "USER_ROLES")
    public class UserRoles implements Serializable {
     
        private static final long serialVersionUID = 1L;
     
        @Id
        @Column(name = "ID")
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long userRolesId;
     
        @Column(unique = true, nullable = false, name = "ROLE_NAME")
        String roleName; 
     
        // getter et setter
    }
    Code pour l'insertion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    User user = new User();
    UserRoles role;
    try {
    	role = userRolesServices.getUserRoleByName("ROLE_USER"); // find jpql - transaction
    } catch (RuntimeException e) {
    	LOGGER.debug("No Roles found");
    	role = new UserRoles("ROLE_USER"); // create new
    }
    user.addUserRole(role);
    user.setUserName(urlId);
    user.setUserForname(fullName);
    user.setUserEmail(email);
    userServices.createUser(user); // em.persist(user) - transaction
    Comme vous pouvez le voir dans le code précédent, la première insertion d'User fonctionne (car le UserRoles n'existe pas, il est crée au moment du persist du User).

    En revanche dès le deuxième persist, comme le UserRoles existe déjà, il est récupéré par userRolesServices.getUserRoleByName("ROLE_USER"); (permettant d'avoir l'id). Mais lorsque j'arrive sur userServices.createUser(user); (persist), j'obtiens l'exception suivante :
    "detached entity to persist : .....UserRoles" (je pense au faite que le getUserRoleByName s'effectue sur une autre transaction).

    Et si je retire le getUserRoleByName (en utilisant directement new UserRoles("ROLE_USER");), j'obtiens l'exception suivante :
    "...ConstraintViolation : Duplicated entry for 'ROLE_NAME' ..."


    Donc ma question est : comment bien gérer le persist d'une relation @ManyToMany ?

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    Pas de réponse ?

  3. #3
    Modérateur
    Avatar de paissad
    Homme Profil pro
    Ingénieur de développement (Java/JEE/Eclipse RCP,EMF & webMethods)
    Inscrit en
    Avril 2006
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur de développement (Java/JEE/Eclipse RCP,EMF & webMethods)
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 043
    Par défaut
    Bonjour,
    est ce que tu as fait les @Override sur tes méthodes equals() et hashCode() afin de ne pas prendre en compte les champs qu'il ne faut pas (comme les champs "id" par exemple ?)
    Dans ta classe UserRoles en l'occurrence, si tu n'as pas fait l'@Override sur equals() et hashCode() alors tu te retrouveras avec un role1.equlas(role2) à false et ceci même si role1 et role2 ont le même nom car par défaut, l'attribut "userRolesId" est pris en compte dans la comparaison.
    L'erreur venait probablement du fait que, lorsque tu faisais un "em.persit()", et vu que tu es en Cascade.ALL, JPA va tenter de vérifier si le 'role' existe ou non afin de le créer, le modifier ou ne rien faire ...

    En général, on ne prend pas en compte les "id" auto générées lors des equals() car il ne font pas souvent partie de la logique de comparaison.

    Cordialement
    Nous n'héritons pas de la terre de nos parents, nous l'empruntons à nos enfants.
    Le chat du site est aussi ici pour aider. Ne pas hésiter à visiter !

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    Malheureusement j'ai bien redéfinit les méthodes equals et hashCode (première chose que j'ai testé), avec le code suivant :
    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
    @Override
    public int hashCode() {
    	final int prime = 31;
    	int result = 1;
    	result = prime * result + ((roleName == null) ? 0 : roleName.hashCode());
    	return result;
    }
     
    @Override
    public boolean equals(Object obj) {
    	if (this == obj)
    		return true;
    	if (obj == null)
    		return false;
    	if (getClass() != obj.getClass())
    		return false;
    	UserRoles other = (UserRoles) obj;
    	if (roleName == null) {
    		if (other.roleName != null)
    			return false;
    	} else if (!roleName.equals(other.roleName))
    		return false;
    	return true;
    }
    Actuellement mon implementation de JPA (Hibernate) n'a pas l'air de vérifier si le rôle existe ou non. S'il n'a pas d'id, il persist !

    En revanche je n'ai pas redéfinit equals et hashCode pour ma classe User

  5. #5
    Modérateur
    Avatar de paissad
    Homme Profil pro
    Ingénieur de développement (Java/JEE/Eclipse RCP,EMF & webMethods)
    Inscrit en
    Avril 2006
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur de développement (Java/JEE/Eclipse RCP,EMF & webMethods)
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 043
    Par défaut
    En fait, ce que je te disais est valable pour tous les @Entity, pas seulement pour UserRoles.
    Nous n'héritons pas de la terre de nos parents, nous l'empruntons à nos enfants.
    Le chat du site est aussi ici pour aider. Ne pas hésiter à visiter !

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    130
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 130
    Par défaut
    Oui je me doute mais dans ma logique, ça fonctionne ainsi :

    Persist User -> vérification que le UserRoles existe (grâce à hashCode et equals). Si non présent -> persist. Puis persist relation dans le join table.
    (donc pas d'utilité de hashCode et equals pour User à priori...(je sasi c'est mieux de le faire))


    Mais j'ai plus l'impression qu'il fonctionne ainsi :
    Persist User -> Si UserRoles n'a pas d'Id : persist (ne gère pas les contraintes d'unicités). Sinon, s'il y a d'Id, vérification que l'entity est attachée à la session (transaction) courante. Si non -> exception "detached entity...". Si pas d'exception: persist relation dans la table jointe.

    Tu penses qu'en définissant le equals et hashCode pour User ça fonctionnera ?

Discussions similaires

  1. Relation ManyToMany : Duplicate entry
    Par Ludo_FA dans le forum Doctrine2
    Réponses: 0
    Dernier message: 05/06/2012, 08h54
  2. Réponses: 9
    Dernier message: 09/05/2011, 21h25
  3. ManyToMany Duplicate entry
    Par natoine dans le forum Hibernate
    Réponses: 2
    Dernier message: 19/03/2010, 11h16
  4. (debian,eclipse 3.4)detached entity pased to persist
    Par olivier57b dans le forum JPA
    Réponses: 9
    Dernier message: 07/03/2009, 12h27
  5. [EJB3 Entity] detached entity passed to persist
    Par maysam dans le forum Java EE
    Réponses: 3
    Dernier message: 03/12/2008, 13h43

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