Qual è la differenza tra CascadeType.REMOVE e orphanRemoval in JPA?


101

Qual è la differenza tra

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

e

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

Questo esempio è tratto da Java EE Tutorial, ma ancora non capisco i dettagli.


La rimozione orfana significa che le entità dipendenti vengono rimosse quando la relazione con la loro entità "genitore" viene distrutta.
Rahul Tripathi

1
Ha scritto un test case che potrebbe illustrare il concetto.
Martin Andersson

Risposte:


153

Da qui : -

Rimozione a cascata

Contrassegnare un campo di riferimento con CascadeType.REMOVE (o CascadeType.ALL, che include REMOVE) indica che le operazioni di rimozione devono essere sovrapposte automaticamente agli oggetti entità a cui fa riferimento quel campo (più oggetti entità possono essere referenziati da un campo di raccolta):

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

Rimozione di orfani

JPA 2 supporta una modalità di rimozione a cascata aggiuntiva e più aggressiva che può essere specificata utilizzando l'elemento orphanRemoval delle annotazioni @OneToOne e @OneToMany:

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

DIFFERENZA:-

La differenza tra le due impostazioni sta nella risposta alla disconnessione di una relazione. Ad esempio, quando si imposta il campo dell'indirizzo su null o su un altro oggetto Indirizzo.

  • Se viene specificato orphanRemoval = true, l'istanza di Address scollegata viene automaticamente rimossa. Ciò è utile per ripulire gli oggetti dipendenti (ad es. Indirizzo) che non dovrebbero esistere senza un riferimento da un oggetto proprietario (ad es. Employee).
  • Se viene specificato solo cascade = CascadeType.REMOVE, non viene eseguita alcuna azione automatica poiché la disconnessione di una relazione non è un'operazione di rimozione
    .

87

Un modo semplice per capire la differenza tra CascadeType.REMOVEe orphanRemoval=true.

Per la rimozione orfana: se si richiama setOrders(null), le Orderentità correlate verranno rimosse automaticamente in db.

Per rimuovere la cascata: se si richiama setOrders(null), le Orderentità correlate NON verranno rimosse automaticamente in db.


2
rimuovere === eliminare
Abdull

9

Supponiamo di avere un'entità figlio e un'entità padre. Un genitore può avere più figli.

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

OrphanRemoval è un concetto ORM, indica se il bambino è orfano. dovrebbe anche essere rimosso dal database.

Un bambino è orfano quando non è possibile accedervi dal genitore. Ad esempio, se rimuoviamo il set di oggetti Person (impostandolo su un set vuoto) o lo sostituiamo con un nuovo set, il genitore non può più accedere ai figli nel vecchio set e i bambini sono orfani, quindi i bambini sono condannati a esserlo rimosso anche nel database.

CascadeType.REMOVE è un concetto a livello di database e dice che se il genitore viene rimosso, tutti i suoi record correlati nella tabella figlia devono essere rimossi.


2

Praticamente la differenza sta nel fatto che tu stia cercando di aggiornare i dati (PATCH) o di sostituire completamente i dati (PUT)

Supponiamo che tu elimini il customerrispetto all'uso cascade=REMOVErimuoverà anche gli ordini dei clienti che sembrano intenzionali e utili.

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

Supponiamo ora che l'aggiornamento a customercon orphanRemoval="true"esso cancellerà tutti gli ordini precedenti e li sostituirà con quello fornito. ( PUTin termini di REST API)

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

Senza orphanRemovalvecchi ordini verrebbero mantenuti. ( PATCHin termini di REST API)


1

Poiché questa domanda è molto comune, questa risposta si basa su questo articolo che ho scritto sul mio blog.

CascadeType.REMOVE

La CascadeType.REMOVEstrategia, che puoi configurare esplicitamente:

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

o ereditarlo implicitamente dalla CascadeType.ALLstrategia:

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

consente di propagare l' removeoperazione dall'entità padre alle sue entità figlio.

Quindi, se recuperiamo l' Postentità genitore insieme alla sua commentsraccolta e rimuoviamo l' postentità:

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 eseguirà tre istruzioni di cancellazione:

DELETE FROM post_comment 
WHERE id = 2

DELETE FROM post_comment 
WHERE id = 3

DELETE FROM post 
WHERE id = 1

Le PostCommententità figlio sono state eliminate a causa della CascadeType.REMOVEstrategia, che si comportava come se avessimo rimosso anche le entità figlio.

La strategia di rimozione degli orfani

La strategia di rimozione degli orfani, che deve essere impostata tramite l' orphanRemovalattributo:

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

ti consente di rimuovere la riga della tabella figlia dopo aver rimosso l'entità figlio dalla raccolta.

Quindi, se carichiamo l' Postentità insieme alla sua commentsraccolta e rimuoviamo la prima PostCommentdalla commentsraccolta:

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 eseguirà un'istruzione DELETE per la post_commentriga della tabella associata :

DELETE FROM post_comment 
WHERE id = 2

Per maggiori dettagli su questo argomento, consulta anche questo articolo .

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.