web-dev-qa-db-fra.com

JPA: suppression unidirectionnelle plusieurs-à-un et en cascade

Disons que j'ai une relation unidirectionnelle @ManyToOne comme celle-ci:

@Entity
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    private long id;
}

@Entity
public class Child implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @ManyToOne
    @JoinColumn
    private Parent parent;  
}

Si j'ai un parent P et des enfants C1... Cn En se référant à P, existe-t-il un moyen propre et attrayant dans JPA de supprimer automatiquement les enfants C1... Cn quand P est retiré (c'est-à-dire entityManager.remove(P))? 

Ce que je recherche, c'est une fonctionnalité similaire à ON DELETE CASCADE en SQL.

73
perp

Les relations dans JPA sont toujours unidirectionnelles, sauf si vous associez le parent à l'enfant dans les deux sens. Les opérations REMOVE en cascade du parent à l'enfant nécessiteront une relation du parent à l'enfant (et non l'inverse).

Vous devrez donc faire ceci:

  • Modifiez la relation unidirectionnelle @ManyToOne en un @ManyToOne bidirectionnel ou un @OneToMany unidirectionnel. Vous pouvez ensuite mettre en cascade les opérations REMOVE afin que EntityManager.remove supprime le parent et les enfants. Vous pouvez également spécifier orphanRemoval en tant que true pour supprimer tous les enfants orphelins lorsque l'entité enfant de la collection parent est définie sur null, c'est-à-dire supprimer l'enfant s'il n'est présent dans la collection d'aucun parent.
  • Ou bien, spécifiez la contrainte de clé étrangère dans la table enfant en tant que ON DELETE CASCADE. Vous devrez appeler EntityManager.clear() après avoir appelé EntityManager.remove(parent) car le contexte de persistance doit être actualisé - les entités enfants ne sont pas supposées exister dans le contexte de persistance après avoir été supprimées de la base de données.
63
Vineet Reynolds

Si vous utilisez hibernate en tant que fournisseur JPA, vous pouvez utiliser l'annotation @OnDelete. Cette annotation ajoutera à la relation le déclencheur ON DELETE CASCADE , qui délègue la suppression des enfants à la base de données.

Exemple:

public class Parent {

        @Id
        private long id;

}


public class Child {

        @Id
        private long id;

        @ManyToOne
        @OnDelete(action = OnDeleteAction.CASCADE)
        private Parent parent;
}

Avec cette solution, une relation unidirectionnelle de l’enfant au parent suffit pour supprimer automatiquement tous les enfants. Cette solution ne nécessite aucun écouteur, etc. De plus, une requête telle que DELETE FROM Parent WHERE id = 1 supprimera les enfants.

66
Thomas Hunziker

Créez une relation bidirectionnelle, comme ceci:

@Entity
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
    private Set<Child> children;
}
14
tekumara