Comment persister @ManyToMany relation - entrée en double ou entité détachée
Je veux enregistrer mes entité relation ManyToMany. Mais j'ai un problème lors de la persistance des processus.
Mes entités :
@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
@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 de Service :
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
Première fois, lorsque j'essaie de conserver un Utilisateur avec UserRoles "ROLE_USER", pas de problème. L'utilisateur et UserRoles et des tables de jointure sont insérés.
Mon problème est que lorsque j'essaie de conserver un deuxième Utilisateur avec le même UserRoles.
- Je vérifier si le UserRoles existe par le trouver (userRolesServices.getUserRoleByName(...)).
Si existe -> ajouter ce UserRoles à la liste des Utilisateurs (id + nom de rôle) sinon je en créer un nouveau (seulement le nom du rôle).
Quand j'essaie de faire persister le deuxième Utilisateur, - je obtenir de l'exception suivante :
", séparé de l'entité de persister : .....UserRoles" (peut-être parce que getUserRoleByName est effectuée dans le cadre d'une autre opération)
Si je n'utilise pas getUserRoleByName (uniquement *nouveau UserRoles("ROLE_USER");*), j'obtiens l'exception suivante :
"...ConstraintViolation : entrée Dupliquée pour "ROLE_NAME' ..."
Alors, comment bien persister une entité avec @ManyToMany relation ?
source d'informationauteur Aure77 | 2012-03-22
Vous devez vous connecter pour publier un commentaire.
Pour le problème ci-dessus, je dirais que votre entité-relation cascade est faux. Considérez ceci: Un utilisateur peut avoir plusieurs rôles, mais il peut être fixé certain nombre de rôles qui peuvent exister dans le système. Donc en CASCADE TOUT de
User
entité n'a aucun sens, puisque le cycle de vie deUserRoles
ne doit pas dépendre deUser
entité cycle de vie. E. g. quand on enlèveUser
UserRoles
ne doivent pas être supprimés.détaché de l'entité à persister exception ne se produit que si vous êtes de passage de l'objet qui a la clé primaire d'ores et déjà persistent.
Supprimer en cascade et votre problème sera résolu maintenant, la seule chose que vous devez décider est de savoir comment vous allez insérer des rôles d'Utilisateur. Selon moi, il devrait être séparée de la fonctionnalité de le faire.
Aussi, ne pas utiliser
ArrayList
utilisezHashSet
.ArrayList
permet de doublons.Je vais donner ma réponse si quelqu'un d'obtenir le même type de problème pour moi et l'auteur.
Fondamentalement, ce que j'ai été confronté a une situation où j'ai eu une table qui était une sorte de CONSTANTE valeurs. Et l'autre de changer, mais il faut la carte (
many to many
) à ceux CONSTANTES.Le problème exact est
USERS
et c'estROLES
.Roles
serait connue et ajoutée au démarrage du système, il convient donc de ne jamais obtenir retiré. Même si aucun utilisateur n'aurait certainsRole
il devrait encore dans le système.L'implémentation de la classe, en utilisant JPA:
Utilisateur:
Rôle:
Utilisation
Cette configuration sera facilement ajouter/supprimer des
Role
àUser
. Tout simplement en passant un tableau, f.e.:user.getRoles().add(new Role("ADMIN"));
etmerge
lauser
. Retrait des œuvres avec le passage d'une liste vide.Si vous oubliez d'ajouter l'
Role
avant de l'ajouter à l'utilisateur plus probable que vous obtiendrez une erreur de ce type:Quoi et pourquoi
mappedBy
attribut est ajouté à l'enfant Entité tel que décrit dans la JPA Docscascade = {CascadeType.MERGE}
est ajouté pour une bonne cascades JPA DocsQui semblent à la le problème, procédez de la requête de la même transaction ou de la personne morale gestionnaire. Sinon re-trouver dans la transaction en cours, utilisez la fonction find().