2010-06-29 10 views
5

In graal, posso implementare un N: 1 rapporto in questo modo:Quando deve essere usato Many per le relazioni N: 1 nelle classi di dominio Grails?

class Parent { hasMany = [children:Child] } 
class Child { belongsTo = [parent:Parent] } 

Ora (se addto e removeFrom è sempre usato correttamente) posso ottenere i figli di un genitore tramite parent.children.

Ma ho anche possibile farlo senza hasMany:

class Parent { } 
class Child { belongsTo = [parent:Parent] } 

allora devo usare Child.findAllByParent (genitore) per ottenere tutti i bambini.

La mia domanda: ci sono motivi importanti per cui dovrei usare hasMany se posso interrogare i figli di un genitore anche nel secondo modo?

Immagino che a volte sia più facile (e forse più veloce se impaziente insieme al genitore?) Di fare semplicemente riferimento a genitore.children, ma d'altra parte questo elenco può diventare piuttosto lungo quando ci sono diversi bambini. E ciò che non mi piace di ManyMany o è che devi sempre prenderti cura di addTo o removeFrom o cancellare la sessione dopo aver aggiunto un nuovo Child con un Parent così che grails lo faccia automaticamente ...

Is la risposta che dovresti semplicemente usare haMany se ci sono pochi bambini e non usarla se ce ne sono molti (per ragioni di prestazioni) o ce ne sono altri dietro?

risposta

8

Utilizzo di hasMany rispetto a belongsTo è più correlato al comportamento a cascata che si desidera specificare quando si verifica un aggiornamento/eliminazione. Nel secondo esempio, il collegamento in cascata è impostato su ALL sul lato figlio e NONE sul lato padre. Se elimini un bambino, non succederà nulla sul genitore. Se elimini il genitore, tutti i bambini saranno automaticamente cancellati.

Nel primo esempio, il collegamento in cascata è impostato su ALL sul lato padre e SAVE-UPDATE sul lato figlio. Quindi ora puoi fare qualcosa del tipo:

parent.addToChildren(child1) 
parent.addToChildren(child2) 
parent.addToChildren(child3) 
parent.save(flush:true) 

E quando salvi il genitore, tutti i bambini saranno aggiornati.

Toccando su qualcosa che non hai chiesto, si potrebbe anche presumibilmente avere qualcosa di simile:

class Parent { hasMany = [children:Child] } 
class Child { Parent parent } 

Se si definisce la relazione da bambino a Parent in questo modo, è necessario gestire manualmente gli oggetti figlio che fa riferimento al genitore quando cancelli il genitore *. (* Questo corregge una dichiarazione precedente che si è rivelata imprecisa)

Così, il hasMany/belongsTo ha due considerazioni principali:

  1. Che tipo di strategia a cascata vuoi eseguire su aggiornamenti/eliminare
  2. Come è probabile che accederai ai dati, se ti aspetti di dover recuperare un gruppo di figli per un genitore, avere un metodo parent.getChildren() è piuttosto conveniente.

UPDATE:

voglio anche chiarire, GORM NON ansioso-fetch quando si utilizza hasMany; per impostazione predefinita GORM utilizza una strategia di recupero lazy in modo che non sia in grado di richiamare i figli fino al tentativo di accedere a un genitore.bambini

Se vuoi un'associazione per essere avidamente recuperato per impostazione predefinita, è possibile specificare la mappatura appropriata:

class Parent { 
    hasMany = [children:Child] 
    static mapping = { 
    children lazy:false 
    } 
} 

Infine, lei ha detto che non ti piace che si deve preoccupare della addto/removeFrom sul lato hasMany. Non dovresti farlo se salvi con flush: true.

def parent = Parent.get(id) 
def child = new Child(name:'child1', parent:parent) 
if(child.save(flush:true)) { 
    // both sides of the relationship should be good now 
} 

EDIT: fisso ordine inverso di figlio/genitore default a cascata e malinteso corretto per quanto riguarda come Gorm ha gestito i rapporti senza belongsTo

+0

Grazie, quindi è tutto sul comportamento a cascata. Diresti che le prestazioni non sono un problema quando l'elenco da gestire per i bambini diventa molto grande? Per quanto riguarda il tuo aggiornamento, sfortunatamente il salvataggio con flush: true non è sufficiente per addTo automatico/removeFrom. Come ho appreso nel mio problema con i grails inviati https://cvs.codehaus.org/browse/GRAILS-6356, è necessario cancellare la sessione con sessionFactory.currentSession.clear() se si desidera ottenere questo WITHIN da un test o da un controller . In una produzione scaffoldata, funziona perché la sessione viene cancellata dopo l'azione di salvataggio/aggiornamento di Child. –

+0

Appena testato e sembra che la cancellazione a cascata sia l'opposto di ciò che si afferma all'inizio: Nel mio primo esempio (con hasMany), quando si elimina un genitore, vengono eliminati anche tutti i bambini. Nell'esempio SECONDO (senza hasMany), i bambini devono essere cancellati manualmente prima di eliminare un genitore. –

+0

In realtà i miei test hanno anche rivelato che nel tuo esempio con hasMany e no appartiene, la cancellazione del genitore NON causa ai figli un genitore nullo ma lancia una DataIntegrityViolationException ... Devo impostare i genitori dei bambini a null prima della cancellazione . –

0

grande domanda, e la risposta attualmente accettato è buono. C'è un'altra considerazione importante sulle prestazioni, che è ciò che accade quando aggiungi e salva un nuovo figlio. Nel tuo primo esempio, Grails per impostazione predefinita deve caricare l'intero elenco di bambini dal database prima di inserirlo nel Set, per garantire univocità. Nel secondo caso, no, il che porta a prestazioni molto migliori. Puoi aggirare questo comportamento nel tuo primo esempio definendo i bambini come una "Collezione" come da http://grails.org/doc/latest/guide/single.html#sets,ListsAndMaps

Problemi correlati