Jaka jest różnica między CascadeType.REMOVE a orphanRemoval w JPA?


103

Jaka jest różnica pomiędzy

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

i

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Ten przykład pochodzi z samouczka Java EE, ale nadal nie rozumiem szczegółów.


Usunięcie osierocone oznacza, że ​​jednostki zależne są usuwane, gdy relacja z jednostką „nadrzędną” zostaje zniszczona.
Rahul Tripathi

1
Napisałem przypadek testowy, który może zilustrować tę koncepcję.
Martin Andersson

Odpowiedzi:


153

Od tutaj : -

Kaskadowe usuwanie

Oznaczanie pola odwołania za pomocą CascadeType.REMOVE (lub CascadeType.ALL, które obejmuje REMOVE) wskazuje, że operacje usuwania powinny być automatycznie kaskadowane do obiektów encji, do których odwołuje się to pole (wiele obiektów encji może być przywoływanych przez pole kolekcji):

@Entity
class Employee {
     :
    @OneToOne(cascade=CascadeType.REMOVE)
    private Address address;
     :
}

Usunięcie sierot

JPA 2 obsługuje dodatkowy i bardziej agresywny tryb kaskadowy usuwania, który można określić za pomocą elementu orphanRemoval adnotacji @OneToOne i @OneToMany:

@Entity
class Employee {
     :
    @OneToOne(orphanRemoval=true)
    private Address address;
     :
}

RÓŻNICA:-

Różnica między tymi dwoma ustawieniami polega na odpowiedzi na zerwanie relacji. Na przykład podczas ustawiania pola adresu na wartość null lub do innego obiektu Adres.

  • Jeśli określono orphanRemoval = true, odłączona instancja Address jest automatycznie usuwana. Jest to przydatne do czyszczenia obiektów zależnych (np. Adres), które nie powinny istnieć bez odniesienia od obiektu właściciela (np. Pracownik).
  • Jeśli podano tylko cascade = CascadeType.REMOVE, nie jest podejmowana żadna automatyczna akcja, ponieważ rozłączenie relacji nie jest
    operacją usuwania .

87

Łatwy sposób na zrozumienie różnicy między CascadeType.REMOVEi orphanRemoval=true.

W przypadku usuwania osieroconych: jeśli wywołasz setOrders(null), powiązane Orderjednostki zostaną automatycznie usunięte w bazie danych.

W przypadku kaskady usuwania: w przypadku wywołania setOrders(null)powiązane Orderjednostki NIE zostaną automatycznie usunięte w bazie danych.


2
remove === delete
Abdull

9

Załóżmy, że mamy byt potomny i podmiot nadrzędny. Rodzic może mieć kilkoro dzieci.

@Entity
class parent {
  //id and other fields
 @OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
   Set<Person> myChildern;
}

OrphanRemoval to koncepcja ORM, która mówi, czy dziecko zostało osierocone. należy go również usunąć z bazy danych.

Dziecko zostaje osierocone, gdy nie można uzyskać do niego dostępu od rodzica. Na przykład, jeśli usuniemy zestaw obiektów Person (ustawiając go na pusty zestaw) lub zastąpimy go nowym zestawem, wówczas rodzic nie będzie już miał dostępu do dzieci ze starego zestawu, a dzieci zostaną osierocone, więc dzieci są skazane na usunięte również w bazie danych.

CascadeType.REMOVE to koncepcja na poziomie bazy danych i mówi, że jeśli rodzic zostanie usunięty, wszystkie powiązane rekordy w tabeli podrzędnej powinny zostać usunięte.


2

Praktycznie różnica polega na tym, czy próbujesz zaktualizować dane (PATCH), czy całkowicie je zastąpić (PUT)

Załóżmy, że usuniesz, a customerużycie cascade=REMOVEusunie również zamówienia klientów, które wydają się zamierzone i przydatne.

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

Teraz powiedzmy, że aktualizujesz plik za customerpomocąorphanRemoval="true" nim spowoduje usunięcie wszystkich poprzednich zamówień i zastąpić je z jednym warunkiem. ( PUTpod względem REST API)

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Bez orphanRemovalstarych zamówień byłby zachowany. ( PATCHpod względem REST API)


1

Ponieważ to pytanie jest bardzo częste, odpowiedź opiera się na tym artykule, który napisałem na swoim blogu.

CascadeType.REMOVE

CascadeType.REMOVEStrategii, które można skonfigurować wyraźnie:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();

lub odziedzicz to niejawnie ze CascadeType.ALLstrategii:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();

umożliwia propagowanie removeoperacji z jednostki nadrzędnej do jej jednostek podrzędnych.

Jeśli więc pobierzemy Postjednostkę nadrzędną wraz z jej commentskolekcją i usuniemy postjednostkę:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments
    where p.id = :id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();

entityManager.remove(post);

Hibernate wykona trzy instrukcje usuwania:

DELETE FROM post_comment 
WHERE id = 2

DELETE FROM post_comment 
WHERE id = 3

DELETE FROM post 
WHERE id = 1

Jednostki PostCommentpodrzędne zostały usunięte z powodu CascadeType.REMOVEstrategii, która działała tak, jakbyśmy usunęli również jednostki podrzędne.

Strategia usuwania sierot

Strategia usuwania sierot, którą należy ustawić za pomocą orphanRemovalatrybutu:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

umożliwia usunięcie wiersza tabeli podrzędnej po usunięciu elementu podrzędnego z kolekcji.

Jeśli więc załadujemy Postjednostkę wraz z jej commentskolekcją i usuniemy pierwszą PostCommentz commentskolekcji:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments c
    where p.id = :id
    order by p.id, c.id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();

post.remove(post.getComments().get(0));

Hibernate ma zamiar wykonać instrukcję DELETE dla powiązanego post_commentwiersza tabeli:

DELETE FROM post_comment 
WHERE id = 2

Aby uzyskać więcej informacji na ten temat, zapoznaj się również z tym artykułem .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.