Was ist der Unterschied zwischen CascadeType.REMOVE und orphanRemoval in JPA?


98

Was ist der Unterschied zwischen

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

und

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

Dieses Beispiel stammt aus dem Java EE Tutorial, aber ich verstehe immer noch keine Details.


Verwaiste Entfernung bedeutet, dass abhängige Entitäten entfernt werden, wenn die Beziehung zu ihrer "übergeordneten" Entität zerstört wird.
Rahul Tripathi

1
Schrieb einen Testfall , der das Konzept veranschaulichen könnte.
Martin Andersson

Antworten:


150

Von hier aus : -

Kaskadieren Entfernen

Das Markieren eines Referenzfelds mit CascadeType.REMOVE (oder CascadeType.ALL, einschließlich REMOVE) gibt an, dass Entfernungsvorgänge automatisch an Entitätsobjekte kaskadiert werden sollen, auf die von diesem Feld verwiesen wird (mehrere Entitätsobjekte können von einem Sammlungsfeld referenziert werden):

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

Orphan Removal

JPA 2 unterstützt einen zusätzlichen und aggressiveren Entfernungskaskadenmodus, der mithilfe des orphanRemoval-Elements der Annotationen @OneToOne und @OneToMany angegeben werden kann:

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

UNTERSCHIED:-

Der Unterschied zwischen den beiden Einstellungen liegt in der Reaktion auf das Trennen einer Beziehung. Zum Beispiel, wenn Sie das Adressfeld auf null oder auf ein anderes Adressobjekt setzen.

  • Wenn orphanRemoval = true angegeben wird, wird die Instanz der getrennten Adresse automatisch entfernt. Dies ist nützlich, um abhängige Objekte (z. B. Adresse) zu bereinigen, die ohne Referenz eines Eigentümerobjekts (z. B. Mitarbeiter) nicht vorhanden sein sollten.
  • Wenn nur cascade = CascadeType.REMOVE angegeben ist, wird keine automatische Aktion ausgeführt, da das Trennen einer Beziehung keine Entfernungsoperation
    ist.

86

Ein einfacher Weg, um den Unterschied zwischen CascadeType.REMOVEund zu verstehen orphanRemoval=true.

Zum Entfernen von Waisen: Wenn Sie aufrufen setOrders(null), werden die zugehörigen OrderEntitäten automatisch in db entfernt.

Zum Entfernen der Kaskade: Wenn Sie aufrufen setOrders(null), werden die zugehörigen OrderEntitäten NICHT automatisch in db entfernt.


2
entfernen === löschen
Abdull

9

Angenommen, wir haben eine untergeordnete Entität und eine übergeordnete Entität. Ein Elternteil kann mehrere Kinder haben.

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

Die orphanRemoval ist ein ORM-Konzept, das angibt, ob das Kind verwaist ist. Es sollte auch aus der Datenbank entfernt werden.

Ein Kind ist verwaist, wenn es von seinem Elternteil nicht aufgerufen werden kann. Wenn wir beispielsweise den Personenobjektsatz entfernen (auf einen leeren Satz setzen) oder durch einen neuen Satz ersetzen, kann der Elternteil nicht mehr auf die Kinder im alten Satz zugreifen und die Kinder sind verwaist, sodass die Kinder zum Scheitern verurteilt sind auch in der Datenbank entfernt.

CascadeType.REMOVE ist ein Konzept auf Datenbankebene. Wenn das übergeordnete Element entfernt wird, sollten alle zugehörigen Datensätze in der untergeordneten Tabelle entfernt werden.


2

Praktisch liegt der Unterschied darin, ob Sie versuchen, die Daten zu aktualisieren (PATCH) oder die Daten vollständig zu ersetzen (PUT).

Angenommen, Sie löschen das customerals "Verwenden" cascade=REMOVE, um Kundenbestellungen zu entfernen, die beabsichtigt und nützlich erscheinen.

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

Nun lassen Sie uns sagen , dass Sie ein Update customermit orphanRemoval="true"es wird alle bisherigen Aufträge löschen und ersetzen Sie sie mit der einen zur Verfügung gestellt. ( PUTin Bezug auf REST API)

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

Ohne orphanRemovalalte Bestellungen würde gehalten werden. ( PATCHin Bezug auf REST API)


0

Da diese Frage sehr häufig ist, basiert diese Antwort auf diesem Artikel, den ich in meinem Blog geschrieben habe.

CascadeType.REMOVE

Die CascadeType.REMOVEStrategie, die Sie explizit konfigurieren können:

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

oder erben Sie es implizit von der CascadeType.ALLStrategie:

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

Mit dieser Option können Sie den removeVorgang von der übergeordneten Entität auf die untergeordneten Entitäten übertragen.

Wenn wir also die übergeordnete PostEntität zusammen mit ihrer commentsSammlung abrufen und die postEntität entfernen :

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 führt drei Löschanweisungen aus:

DELETE FROM post_comment 
WHERE id = 2

DELETE FROM post_comment 
WHERE id = 3

DELETE FROM post 
WHERE id = 1

Die PostCommentuntergeordneten Entitäten wurden aufgrund der CascadeType.REMOVEStrategie gelöscht , die so tat, als hätten wir auch die untergeordneten Entitäten entfernt.

Die Strategie zur Entfernung von Waisen

Die Strategie zum Entfernen von Waisen, die über das orphanRemovalAttribut festgelegt werden muss:

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

Mit dieser Option können Sie die untergeordnete Tabellenzeile entfernen, wenn Sie die untergeordnete Entität aus der Sammlung entfernen.

Wenn wir also die PostEntität zusammen mit ihrer commentsSammlung laden und die erste PostCommentaus der commentsSammlung entfernen :

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 führt eine DELETE-Anweisung für die zugehörige post_commentTabellenzeile aus:

DELETE FROM post_comment 
WHERE id = 2

Weitere Informationen zu diesem Thema finden Sie auch in diesem Artikel .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.