Welche Bedeutung hat CascadeType.ALL für eine @ VieleToOne-JPA-Zuordnung?

210

Ich glaube, ich habe die Bedeutung von Kaskadierung im Kontext einer @ManyToOneBeziehung falsch verstanden .

Der Fall:

public class User {

   @OneToMany(fetch = FetchType.EAGER)
   protected Set<Address> userAddresses;

}

public class Address {

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   protected User addressOwner;

}

Was bedeutet das cascade = CascadeType.ALL? Wenn ich beispielsweise eine bestimmte Adresse aus der Datenbank lösche, wie wirkt sich die Tatsache, dass ich die hinzugefügt habe, cascade = CascadeType.ALLauf meine Daten aus (die User, denke ich)?

Forhas
quelle

Antworten:

360

Die Bedeutung von CascadeType.ALList, dass die Persistenz alle EntityManagerOperationen ( PERSIST, REMOVE, REFRESH, MERGE, DETACH) an die zugehörigen Entitäten weitergibt (kaskadiert) .

Es scheint in Ihrem Fall eine schlechte Idee zu sein, da das Entfernen eines Addresszum Entfernen des verwandten führen würde User. Da ein Benutzer mehrere Adressen haben kann, werden die anderen Adressen zu Waisen. Der umgekehrte Fall (Annotieren des User) wäre jedoch sinnvoll - wenn eine Adresse nur einem einzelnen Benutzer gehört, ist es sicher, das Entfernen aller Adressen eines Benutzers zu verbreiten, wenn dieser Benutzer gelöscht wird.

Übrigens: Möglicherweise möchten Sie mappedBy="addressOwner"Ihrem UserPersistenzanbieter ein Attribut hinzufügen , um dem Persistenzanbieter zu signalisieren, dass sich die Join-Spalte in der ADDRESS-Tabelle befinden soll.

kostja
quelle
55
+1 für die beste und kürzeste Erklärung von mappedBy, die mir je begegnet ist.
Ridcully
4
Es könnte jedoch gut sein, CascadeType.ALL auf der Seite von @OneToMany zu haben.
mvmn
48

Hier finden Sie ein Beispiel aus den OpenJPA-Dokumenten. CascadeType.ALLbedeutet, dass alle Aktionen ausgeführt werden.

Zitat:

CascadeType.PERSIST: Wenn Sie eine Entität beibehalten, behalten Sie auch die Entitäten bei, die in ihren Feldern gespeichert sind. Wir empfehlen eine liberale Anwendung dieser Kaskadenregel. Wenn der EntityManager während des Flushs ein Feld findet, das auf eine neue Entität verweist, und das Feld CascadeType.PERSIST nicht verwendet, liegt ein Fehler vor.

CascadeType.REMOVE: Beim Löschen einer Entität werden auch die in diesem Feld enthaltenen Entitäten gelöscht.

CascadeType.REFRESH: Aktualisieren Sie beim Aktualisieren einer Entität auch die in diesem Feld enthaltenen Entitäten.

CascadeType.MERGE: Wenn Sie den Entitätsstatus zusammenführen, führen Sie auch die in diesem Feld enthaltenen Entitäten zusammen.

Sebastian

seba.wagner
quelle
4
Neu in JPA, diese Informationen sind nützlich, aber was ist mit Detach hier?
Sarz
1
In CascadeType.DETACH trennen em beim Trennen einer Entität auch die Entitäten, die von der übergeordneten Entität gehalten werden.
Dorian Mejer
29

Wie ich in erklärte diesen Artikel und in meinem Buch, High Performance Java Persistence , sollten Sie nicht verwenden , CascadeType.ALLauf , @ManyToOneda Unternehmen Zustandsübergänge sollten propagieren von übergeordneten Einheiten zu Kindern diejenigen, nicht umgekehrt.

Die @ManyToOneSeite ist immer die untergeordnete Zuordnung, da sie die zugrunde liegende Fremdschlüsselspalte abbildet.

Daher sollten Sie das Attribut CascadeType.ALLvon der @ManyToOneZuordnung zur @OneToManySeite verschieben, die auch das mappedByAttribut verwenden sollte, da es die effizienteste Zuordnung von Eins-zu-Viele-Tabellenbeziehungen ist .

Vlad Mihalcea
quelle
18

Aus der EJB3.0-Spezifikation :

Die Verwendung des Kaskadenanmerkungselements kann verwendet werden, um den Effekt einer Operation auf zugeordnete Entitäten zu übertragen. Die Kaskadenfunktionalität wird am häufigsten in Eltern-Kind-Beziehungen verwendet.

Wenn X eine verwaltete Entität ist, wird sie durch den Entfernungsvorgang entfernt. Die Entfernungsoperation wird an Entitäten kaskadiert, auf die von X verwiesen wird, wenn die Beziehungen von X zu diesen anderen Entitäten mit dem Annotationselementwert cascade = REMOVE oder cascade = ALL kommentiert werden.

Kurz gesagt, Entitätsbeziehungen, mit denen definiert wurde CascadeType.All, stellen sicher, dass alle Persistenzereignisse wie Persistent, Aktualisieren, Zusammenführen und Entfernen, die auf dem übergeordneten Element auftreten, an das untergeordnete Element übergeben werden. Durch das Definieren anderer CascadeTypeOptionen erhält der Entwickler eine detailliertere Kontrolle darüber, wie die Entitätszuordnung mit der Persistenz umgeht.

Zum Beispiel, wenn ich ein Objektbuch hatte, das eine Liste von Seiten enthielt, und ich ein Seitenobjekt zu dieser Liste hinzufüge. Wenn die @OneToManyAnmerkung, die die Zuordnung zwischen Buch und Seite definiert, als markiert ist CascadeType.All, würde das Beibehalten des Buches dazu führen, dass die Seite auch für die Datenbank beibehalten wird.

Kevin Bowersox
quelle
11

Wenn Sie in JPA 2.0 eine Adresse löschen möchten, wenn Sie sie aus einer Benutzerentität entfernt haben, können Sie sie zu Ihrer Adresse hinzufügen orphanRemoval=true(anstelle von CascadeType.REMOVE) @OneToMany.

Weitere Erklärung zwischen orphanRemoval=trueund CascadeType.REMOVEist hier .

Emilien Brigand
quelle
4

Wenn Sie nur die dem Benutzer zugewiesene Adresse löschen und die Entitätsklasse des Benutzers nicht beeinflussen möchten, sollten Sie Folgendes versuchen:

@Entity
public class User {
   @OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
   protected Set<Address> userAddresses = new HashSet<>();
}

@Entity 
public class Addresses {
   @ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
   protected User addressOwner;
}

Auf diese Weise müssen Sie sich keine Gedanken über die Verwendung von Fetch in Anmerkungen machen. Denken Sie jedoch daran, dass Sie beim Löschen des Benutzers auch die mit dem Benutzerobjekt verbundene Adresse löschen.

szachMati
quelle