Qual è il significato di CascadeType.ALL per un'associazione JPA @ManyToOne


210

Penso di aver frainteso il significato del collegamento a cascata nel contesto di una @ManyToOnerelazione.

Il caso:

public class User {

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

}

public class Address {

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

}

Qual è il significato di cascade = CascadeType.ALL? Ad esempio, se elimino un determinato indirizzo dal database, in che modo il fatto che abbia aggiunto cascade = CascadeType.ALLinfluisca sui miei dati (il User, immagino)?

Risposte:


360

Il significato di CascadeType.ALLè che la persistenza propagherà (a cascata) tutte le EntityManageroperazioni ( PERSIST, REMOVE, REFRESH, MERGE, DETACH) alle entità relative.

Nel tuo caso sembra essere una cattiva idea, in quanto la rimozione di una Addressporterebbe alla rimozione del relativo User. Poiché un utente può avere più indirizzi, gli altri indirizzi diventerebbero orfani. Tuttavia, il caso inverso (annotando il User) avrebbe senso: se un indirizzo appartiene a un solo utente, è sicuro propagare la rimozione di tutti gli indirizzi appartenenti a un utente se questo utente viene eliminato.

A proposito: potresti voler aggiungere un mappedBy="addressOwner"attributo al tuo Userper segnalare al provider di persistenza che la colonna join dovrebbe essere nella tabella ADDRESS.


55
+1 per la migliore e più breve spiegazione di mappedDa cui mi sono mai imbattuto.
Ridcully,

4
Tuttavia, potrebbe essere utile avere CascadeType.ALL sul lato @OneToMany.
mvmn

48

Vedi qui per un esempio dai documenti OpenJPA. CascadeType.ALLsignifica che farà tutte le azioni.

Citazione:

CascadeType.PERSIST: quando persisti un'entità, permetti anche alle entità trattenute nei suoi campi. Suggeriamo un'applicazione liberale di questa regola a cascata, perché se EntityManager trova un campo che fa riferimento a una nuova entità durante il flush e il campo non utilizza CascadeType.PERSIST, si tratta di un errore.

CascadeType.REMOVE: quando si elimina un'entità, elimina anche le entità contenute in questo campo.

CascadeType.REFRESH: quando si aggiorna un'entità, aggiornare anche le entità contenute in questo campo.

CascadeType.MERGE: quando si unisce lo stato entità, unire anche le entità contenute in questo campo.

Sebastian


4
Novità in JPA, queste informazioni sono utili, ma per quanto riguarda Detach qui?
Sarz,

1
In CascadeType.DETACH, quando si stacca un'entità, si staccano anche le entità detenute dall'entità padre.
Dorian Mejer,

29

Come ho spiegato in questo articolo e nel mio libro, ad alte prestazioni Java Persistence , non si dovrebbe usare CascadeType.ALLil @ManyToOnedato che le transizioni di stato entità dovrebbe propagarsi da entità genitore a quelli bambino, non il contrario.

Il @ManyToOnelato è sempre l'associazione figlio poiché mappa la colonna Chiave esterna sottostante.

Pertanto, è necessario spostare il CascadeType.ALLdalla @ManyToOneassociazione al @OneToManylato, che dovrebbe anche utilizzare l' mappedByattributo dal momento che è il più efficiente mappatura rapporto tavolo uno-a-molti .


18

Dalla specifica EJB3.0 :

L'uso dell'elemento di annotazione in cascata può essere usato per propagare l'effetto di un'operazione alle entità associate. La funzionalità a cascata viene generalmente utilizzata nelle relazioni padre-figlio.

Se X è un'entità gestita, l'operazione di rimozione fa sì che venga rimossa. L'operazione di rimozione viene portata in cascata alle entità a cui fa riferimento X, se le relazioni tra X e queste altre entità sono annotate con il valore cascade = REMOVE o cascade = ALL dell'elemento di annotazione.

Quindi, in poche parole, le relazioni di entità definite con CascadeType.Allgarantiranno che tutti gli eventi di persistenza come persistere, aggiornare, unire e rimuovere che si verificano sul genitore, saranno passati al figlio. La definizione di altre CascadeTypeopzioni fornisce allo sviluppatore un livello più granulare di controllo su come l'associazione entità gestisce la persistenza.

Ad esempio, se avessi un Book oggetto che contenesse un Elenco di pagine e aggiungessi un oggetto Pagina all'interno di questo elenco. Se l' @OneToManyannotazione che definisce l'associazione tra Libro e Pagina è contrassegnata come CascadeType.All, la persistenza del Libro comporterebbe anche il persistere della Pagina nel database.


11

In JPA 2.0 se si desidera eliminare un indirizzo se è stato rimosso da un'entità utente, è possibile aggiungere orphanRemoval=true(anziché CascadeType.REMOVE) al proprio @OneToMany.

Altre spiegazioni tra orphanRemoval=truee CascadeType.REMOVEè qui .


4

Se desideri semplicemente eliminare l'indirizzo assegnato all'utente e non influire sulla classe di entità Utente, dovresti provare qualcosa del genere:

@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;
}

In questo modo non devi preoccuparti di usare il recupero nelle annotazioni. Ma ricorda che quando elimini l'Utente eliminerai anche l'indirizzo connesso all'oggetto utente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.