2009-10-07 18 views
11

Nella mia datamodel sono presenti due entità denominate User e UserProfile. Ecco come sono mappati.Una domanda su JPA Cascading

Codice da Entity Utente:

@OneToOne(cascade=CascadeType.ALL) 
@PrimaryKeyJoinColumn 
public UserProfile getUserProfile(){ 
    return this.userProfile; 
} 

public void setUserProfile(UserProfile userProfile){ 
    this.userProfile=userProfile; 
} 

Codice da ProfiloUtente Entità:

@OneToOne(mappedBy="userProfile",cascade=CascadeType.ALL) 
public User getUser(){ 
    return this.user; 
} 

public void setUser(User user){ 
    this.user=user; 
} 

Come vedete, ho un cascadetype.all per l'attributo utente in UserProfile. Ma quando provo a eliminare l'entità UserProfile, l'entità Utente corrispondente rimane ancora. (Quando provo la cancellazione dell'entità utente, corrispondente ProfiloUtente entità viene eliminato.)

Ecco la mia domanda: -

  • fare cascate tengono solo quando li ho specificare sull'entità possedere il rapporto?
+2

le tue prove suggeriscono che la risposta è "sì" – skaffman

+0

@skaffman ..... Quindi, questo è l'unico motivo dietro il concetto di proprietario e di proprietà? O ci sono altri? Grazie. – soontobeared

risposta

3

Come detto

Quando cerco di eliminare l'entità UserProfile, il corrispondente entità utente rimane ancora

Forse quando si tenta di rimuovere un UserProfile si ottiene una violazione di vincolo di integrità dal database - usi il motore MyISAM in MySQL?

Ma come non si dice nulla. Forse la tua entità UserProfile non ha un riferimento a un'entità User.

Come detto nella specifica JPA

rimuovi operazione è collegato in cascata ad entità fa riferimento X, se il rapporto tra X queste altre entità è annotata con la cascata = RIMUOVERE o cascade = ALL valore elemento annotation

Qualcosa di simile

UserProfile up = entityManager.find(UserProfile.class, id); 

entityManager.close(); 

// Notice User is null outside a persistence context 
// So user will be not removed from the database because UserProfile does not have a reference to it 
up.setUser(null); 

entityManager.getTransaction().begin(); 

entityManager.remove(up); 

entityManager.getTransaction().commit(); 

O avete qualcosa come

entityManager.getTransaction().begin(); 

UserProfile up = entityManager.find(UserProfile.class, id); 

// throws UPDATE USER_PROFILE SET USER_ID = NULL 
up.setUser(null); 

// up.getUser() is null 
// So user is not removed 
entityManager.remove(up); 

entityManager.getTransaction().commit(); 

In risposta al commento di ChhsPly:

In Java Persistence con Hibernate libro, si vede il seguente

L'attributo cascade è direzionale: Essa si applica a un solo fine l'associazione.

penso che sarebbe meglio come

Essa si applica a una sola estremità dell'associazione per operazione

Così si può mettere attributo cascade in entrambi i lati allo stesso tempo, anche in una relazione bidirezionale. Quindi ChssPly ha ragione.

attributo mappdeBy imposta la relazione bidirezionale. attributo mappedBy designato come entità inversa della relazione. Ciò significa che l'entità cliente è il lato proprietario della relazione.

ChssPly ha ragione quando dice mappedBy non ha nulla a che fare con cascata

+0

Che non è corretto. Prima di tutto, 'mappedBy' non ha nulla a che fare con il collegamento a cascata: è usato per indicare il lato non proprietario della relazione bidirezionale. In secondo luogo, l'attributo "cascade" è un ** attributo ** (come in "non un'associazione") quindi non è unidirezionale o bidirezionale in sé. Può essere applicato a un'associazione unidirezionale o bidirezionale (compresi entrambi i lati contemporaneamente). Alcuni tipi ** a cascata * potrebbero non avere senso sul lato dell'associazione non proprietario. – ChssPly76

+0

Grazie, ChssPly. Dato che sono un madrelingua inglese non nativo, ho alcune limitazioni quando scrivo una risposta. Aggiunto alla risposta originale. –

+0

@Arthur - grazie per le tue modifiche (upvoting); Non volevo essere duro o pungente al fraseggio, volevo solo chiarire alcuni punti. L'inglese non è la mia prima lingua :-) – ChssPly76

1

che sia corretto quando si ha un rapporto bidirezionale il proprietario detta le regole a cascata dal momento che è il "proprietario". L'entità "posseduta" essenzialmente segue gli ordini, non può dare gli ordini, per così dire.

15

La tua domanda è sbagliata di per sé, da cui deriva tutta la confusione. Arthur ha fatto un buon lavoro con la sua risposta, ma è chiaro dai commenti che la confusione rimane ancora, quindi fammi prendere una pugnalata qui.

fare cascate tengono solo quando ho specificare loro sull'entità possedere il rapporto ?

"cascade" è un attributo specificato su una (o eventualmente entrambe, in caso di bidirezionale) fine di una relazione. Determina quali azioni eseguite eseguite su e che la fine di verrà propagata alla fine . Esistono many different types di quelle azioni definite in JPA e even more definite nelle estensioni Hibernate. Questa distinzione è importante: si dovrebbe parlare solo del comportamento specifico propagato e non "in cascata" in generale.

PERSIST, MERGE, REFRESH si propagano normalmente (dalla fine sono stati dichiarati all'altro).

RIMUOVERE, tuttavia, è difficile perché può significare due cose diverse. Se si dispone di una relazione tra A e B e si sta cercando di rimuovere A, è possibile rimuovere B sull'altra estremità oppure è possibile rimuovere l'associazione ma lasciare B intatto. Hibernate fa una chiara distinzione tra i due: è possibile dichiarare separatamente i tipi REMOVE (DELETE) e DELETE_ORPHAN cascade; Le specifiche JPA no. Si noti che DELETE_ORPHAN non è supportato per le relazioni a valore singolo (OneToOne/ManyToOne).

Così, la propagazione di remove (da solo o quando è parte di ALL) dipende dal fatto rapporto ha un chiaro proprietario (unidirezionale fa sempre; bidirezionale fa se è mappata usando mappedBy e non se è mappato tramite join table) nel qual caso è propagato dal proprietario al proprietario OR nessun proprietario nel qual caso è propagato in entrambe le direzioni ma senza la semantica DELETE_ORPHAN a meno che non sia stato specificato esplicitamente. Tipico esempio di quest'ultimo è bidirezionale molti-a-molti.

+0

Ciao Chss, ho provato qui e funziona bene - OneToOne e ManyToMany. Anche se ho usato Hibernate penso che funzioni nello stesso modo in JPA perché l'ibernazione è un superset del JPA. Penso che sarebbe meglio se avesse mostrato il codice in cui tento di rimuovere UserProfile e la sua entità utente referenziata. Forse una violazione del vincolo viene generata dall'applicazione e l'entità Utente referenziata non viene rimossa. Ancora una volta è difficile supporre quello che è successo. saluti, –

+0

... no. Hibernate è un IMPLEMENTATION di JPA, questo non ha nulla a che fare con un "superset" - che non ha alcun senso – specializt

+1

Sarebbe bello se aggiorni la tua risposta per riflettere il comportamento orfano attuale di JPA 2. –

0

con JPA 2.x, se si vuole una cascata di eliminare il quindi utilizzare orphanRemoval attributo:

@OneToMany(orphanRemoval=true)

controllo documentazione here per maggiori informazioni.