2011-08-25 7 views
63

dire che ho un unidirezionale@ManyToOne rapporto come la seguente:JPA: unidirezionale molti-a-uno e cascata eliminare

@Entity 
public class Parent implements Serializable { 

    @Id 
    @GeneratedValue 
    private long id; 
} 

@Entity 
public class Child implements Serializable { 

    @Id 
    @GeneratedValue 
    private long id; 

    @ManyToOne 
    @JoinColumn 
    private Parent parent; 
} 

Se ho un genitore P e bambini C ... C n riferimento torna a P, c'è un modo pulito e abbastanza in APP a rimuovere automaticamente i bambini C ... C n quando P viene rimossa (cioè entityManager.remove(P))?

Quello che sto cercando è una funzionalità simile a ON DELETE CASCADE in SQL.

+1

Anche se solo "Bambino" ha un riferimento a "Padre" (in questo modo il riferimento è unidirezionale) è problematico aggiungere l'Elenco di "Bambino" con una mappatura "@OneToMany" e "Cascata = ALL" 'attributo al' Genitore '? Suppongo che l'APP dovrebbe risolvere il problema anche se solo 1 lato dura detiene il riferimento. – kvDennis

+1

@kvDennis, ci sono casi in cui non si desidera accoppiare strettamente il lato multiplo di un lato. Per esempio. in configurazioni tipo ACL dove le autorizzazioni di sicurezza sono trasparenti "add-on" – Bachi

risposta

56

Le relazioni in JPA sono sempre unidirezionali, a meno che non si associ il genitore al figlio in entrambe le direzioni. Le operazioni di RIMOZIONE a cascata dal genitore al figlio richiedono una relazione dal genitore al figlio (non solo il contrario).

Avrete quindi bisogno di fare questo:

  • entrambi i casi, cambiare l'unidirezionale @ManyToOne relazione ad un bi-direzionale @ManyToOne, o un unidirezionale @OneToMany. È quindi possibile eseguire in cascata le operazioni di RIMOZIONE in modo che lo EntityManager.remove rimuova padre e figli. È inoltre possibile specificare orphanRemoval come true per eliminare eventuali figli orfani quando l'entità child nella raccolta genitore è impostata su null, ovvero rimuovere il figlio quando non è presente nella raccolta di alcun genitore.
  • Oppure specificare il vincolo di chiave esterna nella tabella figlio come ON DELETE CASCADE. Avrai bisogno di invocare EntityManager.clear() dopo aver chiamato EntityManager.remove(parent) come il contesto di persistenza deve essere aggiornato - le entità figlio non dovrebbero esistere nel contesto di persistenza dopo che sono state cancellate nel database.
+4

c'è un modo per fare No2 con un'annotazione JPA? – user2573153

+2

Come si esegue No2 con i mapping xib di Hibernate? – arg20

+0

la risposta sotto è molto meglio della tua – Enerccio

11

crea una relazione bidirezionale, in questo modo:

@Entity 
public class Parent implements Serializable { 

    @Id 
    @GeneratedValue 
    private long id; 

    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE) 
    private Set<Child> children; 
} 
+0

risposta sbagliata, le relazioni bidirezionali sono terribili in JPA perché l'utilizzo su gruppi di bambini grandi richiede una quantità incredibile di tempo – Enerccio

-1

@Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

annotazione Dato lavorato per me.

Per esempio: -

 public class Parent{ 
      @Id 
      @GeneratedValue(strategy=GenerationType.AUTO) 
      @Column(name="cct_id") 
      private Integer cct_id; 
      @OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER,mappedBy="clinicalCareTeam", orphanRemoval=true) 
      @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) 
      private List<Child> childs; 
     } 
      public class Child{ 
      @ManyToOne(fetch=FetchType.EAGER) 
      @JoinColumn(name="cct_id") 
      private Parent parent; 
    } 
39

Se si utilizza Hibernate come provider JPA è possibile utilizzare il @OnDelete annotazione. Questa annotazione aggiungerà alla relazione il trigger ON DELETE CASCADE, che delega la cancellazione dei figli al database.

Esempio:

public class Parent { 

     @Id 
     private long id; 

} 


public class Child { 

     @Id 
     private long id; 

     @ManyToOne 
     @OnDelete(action = OnDeleteAction.CASCADE) 
     private Parent parent; 
} 

Con questa soluzione un rapporto unidirezionale dal bambino al genitore è sufficiente per rimuovere automaticamente tutti i bambini. Questa soluzione non ha bisogno di ascoltatori, ecc. Anche una query come ELIMINA DA padre DOVE id = 1 rimuoverà i bambini.

+0

Questa è una soluzione perfetta senza modificare il design di @ManyToOne. –

+0

Questa è un'ottima risposta, non è nemmeno un'opzione, è una funzione molto importante. – Yoi

+2

Non riesco a farlo funzionare in questo modo, c'è qualche versione specifica di ibernazione o altri esempi più dettagliati come questo? – Mardari