110 votes

Comment supprimer l’entité relation ManyToMany JPA (et les lignes correspondantes de table de jointure) ?

Disons que j'ai deux entités: le Groupe et l'Utilisateur. Chaque utilisateur peut être membre de plusieurs groupes et chaque groupe peut avoir de nombreux utilisateurs.

@Entity
public class User {
    @ManyToMany
    Set<Group> groups;
    //...
}

@Entity
public class Group {
    @ManyToMany(mappedBy="groups")
    Set<User> users;
    //...
}

Maintenant, je veux supprimer un groupe (disons qu'il a beaucoup de membres).

Le problème est que lorsque j'appelle l'EntityManager.remove() sur certains groupes, fournisseur JPA (dans mon cas, Hibernate) ne pas supprimer des lignes de la table de jointure et de supprimer l'opération échoue en raison de contraintes de clé étrangère. Appel remove() de l'Utilisateur fonctionne très bien (je suppose que cela a quelque chose à voir avec la possession côté de la relation).

Alors, comment puis-je supprimer un groupe dans ce cas?

Seule façon que je pouvais venir avec charge tous les utilisateurs du groupe, puis pour chaque utilisateur supprimer un groupe actuel de ses groupes et de mise à jour de l'utilisateur. Mais il semble ridicule de m'appeler update() sur chaque utilisateur du groupe juste pour être en mesure de supprimer ce groupe.

106voto

Grzegorz Oledzki Points 10491
  • La propriété de la relation est déterminée par l'endroit où vous placez le mappedBy' attribut de l'annotation. L'entité que vous mettez 'mappedBy' est celui qui n'est PAS le propriétaire. Il n'y a aucune chance pour que les deux parties soient propriétaires. Si vous n'avez pas de "supprimer utilisateur" de cas d'utilisation, il vous suffit de déplacer la propriété de l' Group de l'entité, comme c'est actuellement le User est le propriétaire.
  • D'autre part, vous n'avez pas été demander à ce sujet, mais une chose vaut la peine de connaître. L' groups et users ne sont pas combinés les uns avec les autres. Je veux dire, après la suppression de User1 instance de Groupe1.les utilisateurs, l'Utilisateur1.les groupes de collections n'est pas modifié automatiquement (ce qui est assez étonnant pour moi),
  • Dans l'ensemble, je vous suggère de décider qui est le propriétaire. Disons que l' User est le propriétaire. Ensuite, lors de la suppression d'un utilisateur de la relation utilisateur-groupe sera mis à jour automatiquement. Mais lors de la suppression d'un groupe que vous avez à prendre soin de la suppression de la relation à vous-même comme ceci:


entityManager.remove(group)
for (User user : group.users) {
     user.groups.remove(group);
}
...
// then merge() and flush()

52voto

Damian Points 2098

Les ouvrages suivants pour moi. Ajoutez la méthode suivante à l’entité qui n’est pas le propriétaire de la relation (groupe)

N’oubliez pas que pour ce faire, le groupe doit avoir une liste à jour des utilisateurs (ce qui n’est pas faite automatiquement). donc chaque fois que vous ajoutez un groupe à la liste de groupe dans l’entité utilisatrice, vous devez également ajouter un utilisateur à la liste des utilisateurs dans l’entité du groupe.

28voto

jelies Points 111

J'ai trouvé une solution possible, mais... je ne sais pas si c'est une bonne solution.

@Entity
public class Role extends Identifiable {

    @ManyToMany(cascade ={CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name="Role_Permission",
            joinColumns=@JoinColumn(name="Role_id"),
            inverseJoinColumns=@JoinColumn(name="Permission_id")
        )
    public List<Permission> getPermissions() {
        return permissions;
    }

    public void setPermissions(List<Permission> permissions) {
        this.permissions = permissions;
    }
}

@Entity
public class Permission extends Identifiable {

    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name="Role_Permission",
            joinColumns=@JoinColumn(name="Permission_id"),
            inverseJoinColumns=@JoinColumn(name="Role_id")
        )
    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

J'ai essayé et ça marche. Lorsque vous supprimez Rôle également les relations sont supprimés (mais pas de l'Autorisation des entités) et lorsque vous supprimez l'Autorisation, les relations avec les Rôle sont supprimés aussi (mais pas le Rôle de l'instance). Mais nous sommes mappage de relation directe de deux fois et les deux entités sont le propriétaire de la relation. Ceci pourrait causer certains problèmes de mise en veille prolongée? Quel type de problèmes?

Merci!

Le code ci-dessus est à partir d'un autre poste connexe.

3voto

NBW Points 479

Pour ce que ça vaut, j’utilise EclipseLink 2.3.2.v20111125-r10461 et si j’ai une relation unidirectionnelle @ManyToMany j’observe le problème que vous décrivez. Cependant, si je change qu’il s’agit d’une relation bidirectionnelle @ManyToMany je suis en mesure de supprimer une entité du côté non propriétaire et la table de jointure est mis à jour correctement. C’est tout cela sans l’utilisation de tout attribut de la cascade.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X