Powiedzmy, że mam relację jednokierunkową, @ManyToOne
taką jak ta:
@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;
}
Jeśli mam rodzica P i dzieci C 1 ... C n odwołując się z powrotem do P, czy w JPA jest czysty i ładny sposób na automatyczne usuwanie dzieci C 1 ... C n po usunięciu P (tj. entityManager.remove(P)
)?
To, czego szukam, to funkcjonalność podobna do ON DELETE CASCADE
SQL.
java
jpa
jpa-2.0
many-to-one
perp
źródło
źródło
Odpowiedzi:
Relacje w JPA są zawsze jednokierunkowe, chyba że skojarzysz rodzica z dzieckiem w obu kierunkach. Kaskadowe operacje USUŃ od rodzica do dziecka będą wymagały relacji między rodzicem a dzieckiem (nie tylko odwrotnie).
Dlatego musisz to zrobić:
@ManyToOne
relację jednokierunkową na dwukierunkową@ManyToOne
lub jednokierunkową@OneToMany
. Następnie możesz kaskadowo wykonać operacje USUŃ, abyEntityManager.remove
usunąć rodzica i dzieci. Możesz również określićorphanRemoval
jako true, aby usunąć osierocone elementy potomne, gdy element podrzędny w kolekcji nadrzędnej ma wartość null, tj. Usunąć dziecko, gdy nie ma go w żadnej kolekcji nadrzędnej.ON DELETE CASCADE
. Będziesz musiał wywołaćEntityManager.clear()
po wywołaniu,EntityManager.remove(parent)
ponieważ kontekst trwałości musi zostać odświeżony - jednostki podrzędne nie powinny istnieć w kontekście trwałości po ich usunięciu z bazy danych.źródło
Jeśli używasz hibernacji jako dostawcy JPA, możesz użyć adnotacji @OnDelete. Ta adnotacja doda do relacji wyzwalacz ON DELETE CASCADE , który deleguje usuwanie elementów podrzędnych do bazy danych.
Przykład:
public class Parent { @Id private long id; } public class Child { @Id private long id; @ManyToOne @OnDelete(action = OnDeleteAction.CASCADE) private Parent parent; }
Dzięki takiemu rozwiązaniu wystarczy jednokierunkowa relacja między dzieckiem a rodzicem, aby automatycznie usunąć wszystkie dzieci. To rozwiązanie nie wymaga żadnych detektorów itp. Również zapytanie takie jak DELETE FROM Parent WHERE id = 1 usunie elementy podrzędne.
źródło
@OneToOne
jakieś pomysły, jak to rozwiązać@OneToOne
?Utwórz relację dwukierunkową, taką jak ta:
@Entity public class Parent implements Serializable { @Id @GeneratedValue private long id; @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE) private Set<Child> children; }
źródło
Widziałem w jednokierunkowym @ManytoOne, usuwanie nie działa zgodnie z oczekiwaniami. Gdy usuwany jest rodzic, najlepiej byłoby również usunąć dziecko, ale tylko rodzic jest usuwany, a dziecko NIE jest usuwane i pozostaje osierocone
Zastosowane technologie to Spring Boot / Spring Data JPA / Hibernate
Sprint Boot: 2.1.2.RELEASE
Spring Data JPA / Hibernate służy do usuwania wiersza .eg
parentRepository.delete(parent)
ParentRepository rozszerza standardowe repozytorium CRUD, jak pokazano poniżej
ParentRepository extends CrudRepository<T, ID>
Oto moja klasa encji
@Entity(name = “child”) public class Child { @Id @GeneratedValue private long id; @ManyToOne( fetch = FetchType.LAZY, optional = false) @JoinColumn(name = “parent_id", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) private Parent parent; } @Entity(name = “parent”) public class Parent { @Id @GeneratedValue private long id; @Column(nullable = false, length = 50) private String firstName; }
źródło
spring.jpa.hibernate.use-new-id-generator-mappings=true spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
"
kod. Zobaczname= "parent"
W ten sposób usuń tylko jedną stronę
@ManyToOne(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY) // @JoinColumn(name = "qid") @JoinColumn(name = "qid", referencedColumnName = "qid", foreignKey = @ForeignKey(name = "qid"), nullable = false) // @JsonIgnore @JsonBackReference private QueueGroup queueGroup;
źródło
@Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
Podana adnotacja zadziałała dla mnie. Można spróbować
Na przykład :-
public class Parent{ @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="cct_id") private Integer cct_id; @OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER,mappedBy="clinicalCareTeam", orphanRemoval=true) @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) private List<Child> childs; } public class Child{ @ManyToOne(fetch=FetchType.EAGER) @JoinColumn(name="cct_id") private Parent parent; }
źródło
Nie musisz używać asocjacji dwukierunkowej zamiast swojego kodu, wystarczy dodać CascaType.Remove jako właściwość do adnotacji ManyToOne, a następnie użyć @OnDelete (action = OnDeleteAction.CASCADE), to działa dobrze dla mnie.
źródło