NHibernate: le proprietà dell'elenco padre e le proprietà figlio correlate non sono sincronizzate

StackOverflow https://stackoverflow.com/questions/1809032

Domanda

Ho due oggetti correlati: ProgramSession e ProgramTask, con una relazione uno-a-molti. Una ProgramSession ha molti ProgramTasks. Quindi gli oggetti si presentano così:

public class ProgramSession
{
    public virtual IList<ProgramTask> ProgramTasks
    {
        get { return _programTasks; }
        set { _programTasks = value; }
    }
}

public class ProgramTask
{
    public virtual ProgramSession ProgramSession
    {
        get { return _programSession; }
        set { _programSession = value; }
    }
}

E i mapping ...

ProgramSession.hbm.xml

<bag name="ProgramTasks" lazy="false" cascade="all-delete-orphan" inverse="true" >
    <key column="SessionUid"></key>
    <one-to-many class="ProgramTask"></one-to-many>
</bag>

ProgramTask.hbm.xml

<many-to-one name="ProgramSession" column="SessionUid" class="ProgramSession" />

I problemi iniziano quando provo a cambiare la ProgramSession di un ProgramTask.

Se rimuovo ProgramTask dalla proprietà dell'elenco ProgramSession.ProgramTasks della vecchia sessione e quindi lo aggiungo alla stessa proprietà nella nuova sessione, NHibernate mi informa che verrà salvato un oggetto eliminato.

Se cambio semplicemente il valore dell'oggetto ProgramTask.ProgramSession, non ho problemi a salvare. Tuttavia, ottengo un comportamento strano se non si salva immediatamente perché le proprietà ProgramSession.ProgramTasks (su entrambe le sessioni) non vengono sincronizzate fino a quando non viene aggiornata la sessione NHibernate.

La modifica dell'oggetto ProgramTask.ProgramSession senza modificare direttamente anche gli elenchi, crea uno stato non valido. Prendi il seguente codice come esempio:

programTask.ProgramSession = newProgramSession;
Assert.That(newProgramSession.ProgramTasks.Contains(programTask)); // fails
Assert.That(!oldProgramSession.ProgramTasks.Contains(programTask)); // fails

Ciò è più problematico nel codice eseguito in seguito, presupponendo che le raccolte ProgramTasks siano sincronizzate con la proprietà ProgramSession. Ad esempio:

foreach(var programTask in programSession.ProgramTasks)
{
    // whatever
}

Un trucco che ho usato per aggirare questo è stato quello di interrogare l'elenco. Non posso usarlo ovunque, ed è chiaramente una cattiva soluzione, ma sottolinea il problema:

var tasksActuallyInSession =
    programSession.ProgramTasks
        .Where(task => task.ProgramSession == programSession)
        .ToList();

Esiste un modo per gestire questo tipo di situazione? Una buona pratica? Sto facendo qualcosa di sbagliato? La mappatura è errata? C'è qualche bandiera NHibernate super segreta che devo impostare?

È stato utile?

Soluzione

Non sono sicuro di aver capito tutto quello che stai facendo qui. Alcuni pensieri:

Se decidi di spostare ProgramTasks , diventano indipendenti e non dovrebbero essere mappati usando cascade = " all-delete-orphan " . Se lo fai, NH rimuove il ProgramTask dal database quando lo rimuovi da un ProgramSession .

Mappalo usando cascade = " none " e controlla tu stesso il ciclo di vita dell'oggetto. (ciò significa: memorizzalo prima che venga archiviato un ProgramSession . Eliminalo quando non viene più utilizzato.)

Non sono sicuro che anche questo sia un problema, ma nota che se hai un riferimento inverso, il tuo codice è responsabile di rendere coerenti i riferimenti. Naturalmente, i riferimenti vengono ripuliti dopo essere stati archiviati nel database e caricati in una sessione vuota, questo perché nel database è presente una sola chiave esterna. Ma non è così che dovrebbe essere fatto. NH non è responsabile della gestione dei riferimenti. (La sua unica responsabilità è di persistere in ciò che stai facendo in memoria.) Quindi devi renderlo coerente in memoria e implementare la tua logica aziendale come se non ci fosse NHibernate dietro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top