234 Stimmen

Wie unterscheidet sich JPA orphanRemoval=true von der ON DELETE CASCADE DML-Klausel?

Ich bin ein wenig verwirrt über das JPA 2.0 orphanRemoval Attribut.

Ich glaube, ich sehe, dass es notwendig ist, wenn ich die DB-Generierungstools meines JPA-Anbieters verwende, um das zugrunde liegende Datenbank-DDL zu erstellen, um ein ON DELETE CASCADE auf der speziellen Beziehung zu haben.

Aber wenn die DB existiert und bereits ein ON DELETE CASCADE auf der Beziehung hat, ist das nicht genug, um die Löschung angemessen zu cascaden? Was macht das orphanRemoval zusätzlich?

372voto

axtavt Punkte 233070

orphanRemoval hat nichts mit ON DELETE CASCADE zu tun.

orphanRemoval ist eine vollständig ORM-spezifische Sache. Es kennzeichnet die "Child"-Entität, die entfernt werden soll, wenn sie nicht mehr von der "Parent"-Entität referenziert wird, z.B. wenn Sie die Child-Entität aus der entsprechenden Sammlung der Parent-Entität entfernen.

ON DELETE CASCADE ist eine datenbankspezifische Sache, die die "Child"-Zeile in der Datenbank löscht, wenn die "Parent"-Zeile gelöscht wird.

4 Stimmen

Bedeutet dies, dass sie die gleiche Wirkung haben, aber ein anderes System dafür verantwortlich ist, dass dies geschieht?

136 Stimmen

Anon, es hat nicht den gleichen Effekt. ON DELETE CASCADE besagt der DB, alle Kindersätze zu löschen, wenn das Elternelement gelöscht wird. Das bedeutet, wenn ich die RECHNUNG lösche, lösche dann alle POSTEN auf dieser RECHNUNG. OrphanRemoval sagt dem ORM, dass wenn ich ein Artikelobjekt aus der Sammlung von Artikeln entferne, die zu einem Rechnungsobjekt gehören (in einer Speicheroperation) und dann die Rechnung "speichere", der entfernte Artikel aus der zugrunde liegenden DB gelöscht werden soll.

5 Stimmen

Wenn Sie eine unidirektionale Beziehung verwenden, wird das Waisenkind automatisch entfernt, auch wenn Sie orphanRemoval = true nicht setzen.

134voto

forhas Punkte 10861

Ein Beispiel aus hier entnommen:

Wenn ein Employee-Entity-Objekt entfernt wird, wird die Löschoperation auf das referenzierte Address-Entity-Objekt übertragen. In diesem Zusammenhang sind orphanRemoval=true und cascade=CascadeType.REMOVE identisch, und wenn orphanRemoval=true angegeben ist, ist CascadeType.REMOVE überflüssig.

Der Unterschied zwischen den beiden Einstellungen liegt in der Reaktion auf das Trennen einer Beziehung. Zum Beispiel, wenn das Adressfeld auf null oder auf ein anderes Address-Objekt gesetzt wird.

  • Wenn orphanRemoval=true angegeben ist, wird die getrennte Address-Instanz automatisch entfernt. Dies ist nützlich zum Aufräumen von abhängigen Objekten (z. B. Address), die ohne Referenz von einem Besitzerobjekt (z. B. Employee) nicht existieren sollten.

  • Wenn nur cascade=CascadeType.REMOVE angegeben ist, wird keine automatische Aktion ausgeführt, da das Trennen einer Beziehung keine Löschoperation ist.

Um hängende Verweise aufgrund von Orphanauslöschung zu vermeiden, sollte dieses Feature nur für Felder aktiviert werden, die private nicht gemeinsam genutzte abhängige Objekte enthalten.

Ich hoffe, dass dies es klarer macht.

0 Stimmen

Nachdem ich deine Antwort gelesen habe, habe ich den genauen Unterschied zwischen beiden erkannt und mein Problem wurde gelöst. Ich hatte Schwierigkeiten, die Kind-Entitäten aus der Datenbank zu löschen, wenn sie aus der definierten Sammlung in der Elternentität entfernt wurden. Deshalb habe ich die Frage 'stackoverflow.com/questions/15526440/…' gestellt. Ich füge meinen Kommentar hinzu, um beide Fragen zu verbinden.

0 Stimmen

@forhas Bitte gehen Sie die Frage durch stackoverflow.com/questions/58185249/…

53voto

Onur Punkte 929

Der Moment, in dem Sie eine untergeordnete Entität aus der Sammlung entfernen, entfernen Sie auch diese untergeordnete Entität aus der Datenbank. Das orphanRemoval impliziert auch, dass Sie keine Eltern ändern können; wenn es eine Abteilung gibt, die Mitarbeiter hat, und Sie entfernen diesen Mitarbeiter, um ihn in eine andere Abteilung zu stellen, haben Sie diesen Mitarbeiter unabsichtlich bei flush/commit (was auch immer zuerst kommt) aus der Datenbank entfernt. Die Moral ist, orphanRemoval auf true zu setzen, solange Sie sicher sind, dass die Kinder dieses Elternteils während ihres gesamten Bestehens nicht zu einem anderen Elternteil migrieren. Wenn orphanRemoval aktiviert ist, wird automatisch auch REMOVE zur Cascade-Liste hinzugefügt.

3 Stimmen

Genau richtig... auch als "privates" Eltern-Kind-Verhältnis bezeichnet.

2 Stimmen

Das bedeutet, dass sobald ich department.remove(emp); aufrufe, wird dieser Mitarbeiter aus der emp Tabelle gelöscht, ohne dass commit() aufgerufen wird.

45voto

Vlad Mihalcea Punkte 121171

Zustandsübergänge von Entitäten

JPA übersetzt Zustandsübergänge von Entitäten in SQL-Anweisungen wie INSERT, UPDATE oder DELETE.

Zustandsübergänge von JPA-Entitäten

Wenn Sie eine Entität persistieren, planen Sie die Ausführung der INSERT-Anweisung, wenn der EntityManager automatisch oder manuell geflusht wird.

Wenn Sie eine Entität entfernen, planen Sie die DELETE-Anweisung, die ausgeführt wird, wenn der Persistenzkontext geflusht wird.

Kaskadierende Zustandsübergänge von Entitäten

Zu Ihrer Bequemlichkeit erlaubt JPA das Weiterleiten von Zustandsübergängen von Elternentitäten zu Kindentitäten.

Also, wenn Sie eine Elternentität Post haben, die eine @OneToMany-Assoziation mit der Kindentität PostComment hat:

Post- und PostComment-Entitäten

Die comments-Sammlung in der Entität Post ist wie folgt gemappt:

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

CascadeType.ALL

Das cascade-Attribut sagt dem JPA-Anbieter, die Zustandsübergänge der Elternentität Post auf alle PostComment-Entitäten weiterzuleiten, die in der comments-Sammlung enthalten sind.

Also, wenn Sie die Post-Entität entfernen:

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

entityManager.remove(post);

Der JPA-Anbieter wird zuerst die PostComment-Entität entfernen, und wenn alle Kindentitäten gelöscht sind, wird er auch die Post-Entität löschen:

DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2

DELETE FROM post WHERE id = 1

Orphan removal

Wenn Sie das orphanRemoval-Attribut auf true setzen, plant der JPA-Anbieter eine remove-Operation, wenn die Kindentität aus der Sammlung entfernt wird.

Also, in unserem Fall,

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());

post.getComments().remove(postComment);

Der JPA-Anbieter wird den zugehörigen post_comment-Datensatz entfernen, da die PostComment-Entität nicht mehr in der comments-Sammlung referenziert wird:

DELETE FROM post_comment WHERE id = 1

ON DELETE CASCADE

Das ON DELETE CASCADE wird auf der FK-Ebene definiert:

ALTER TABLE post_comment 
ADD CONSTRAINT fk_post_comment_post_id 
FOREIGN KEY (post_id) REFERENCES post 
ON DELETE CASCADE;

Wenn Sie das tun, und eine post-Zeile löschen:

DELETE FROM post WHERE id = 1

Werden automatisch alle zugehörigen post_comment-Entitäten von der Datenbank-Engine entfernt. Dies kann jedoch eine sehr gefährliche Operation sein, wenn Sie versehentlich eine Stamm-Entität löschen.

Fazit

Der Vorteil der JPA-Optionen cascade und orphanRemoval ist, dass Sie auch von optimistischem Sperren profitieren können, um verlorene Updates zu verhindern.

Wenn Sie den JPA-Kaskadierungsmechanismus verwenden, müssen Sie nicht das DDl-Level ON DELETE CASCADE verwenden, was eine sehr gefährliche Operation sein kann, wenn Sie eine Stamm-Entität löschen, die viele Kind-Entitäten auf mehreren Ebenen hat.

0 Stimmen

Also im Abschnitt zur Waisenentfernung Ihres Antwortposts.getComments().remove(postComment); wird nur bei bidirektionaler OneToMany-Zuordnung aufgrund der Persistenzkaskade funktionieren. Ohne Kaskadierung und ohne Entfernung auf der ManyToOne-Seite, wie in Ihrem Beispiel, würde die Entfernung der Verbindung zwischen den 2 Entitäten nicht in der DB gespeichert werden?

0 Stimmen

Die Entfernung von Waisen wird nicht von CascadeType beeinflusst. Es handelt sich um einen ergänzenden Mechanismus. Sie verwechseln jetzt Entfernung mit Persistieren. Die Waisenentfernung bezieht sich darauf, nicht referenzierte Zuordnungen zu löschen, während das Persistieren das Speichern neuer Entitäten betrifft. Um ein besseres Verständnis dieser Konzepte zu erhalten, müssen Sie den in der Antwort bereitgestellten Links folgen.

1 Stimmen

Ich verstehe eine Sache nicht: Wie wird die Waisenentfernung im bidirektionalen Mapping ausgelöst, wenn wir niemals die Verbindung auf der M-Seite entfernen? Ich denke, dass das Entfernen eines PostComment aus der Liste von Post ohne PostComment.post auf null zu setzen, nicht dazu führen wird, dass die Verbindung zwischen diesen beiden Entitäten in der Datenbank entfernt wird. Deshalb glaube ich nicht, dass die Waisenentfernung ausgelöst wird, in der relationalen Welt ist der PostComment kein Waise. Ich werde es testen, wenn ich etwas freie Zeit habe.

21voto

Heri Punkte 2114

Das äquivalente JPA-Mapping für das DDL ON DELETE CASCADE ist cascade=CascadeType.REMOVE. Wenn die Option "Orphan Removal" aktiviert ist, werden abhängige Entitäten entfernt, wenn die Beziehung zu ihrer "übergeordneten" Entität zerstört wird. Zum Beispiel, wenn ein Kind aus einer @OneToMany-Beziehung entfernt wird, ohne es explizit im Entity Manager zu entfernen.

1 Stimmen

cascade=CascadeType.REMOVE ist NICHT gleichbedeutend mit ON DELETE CASCADE. Entfernen Sie im Anwendungscode und beeinflusst nicht beim DDL, andere Aktionen werden in der Datenbank ausgeführt. Siehe stackoverflow.com/a/19696859/548473

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X