papo we(b)log

software engineering slave!
posts - 29, comments - 49, trackbacks - 26

NHibernate e session-per-conversation

Dopo aver trascorso l'ennesima mattinata a cercare di fixare un bug nel mio DAL con NHibernate, finalmente si è aperto uno spiraglio di luce. E ho deciso di farvene (brevemente!) partecicpi.

Si tratta del pattern per il ciclo di vita Session per Conversation, proposto con Hibernate. In sostanza, si fa conicidere una "conversation" con l'intera durata di una transazione al livello business (come la realizzazione di un itero caso d'uso), e si esegue il commit solo alla fine. Le varie fasi intermedie (finestre di un wizard o pagine web che sia) accumulano richieste al DataAccess (ognuna racchiusa da una transazione) usando la stessa Session, che nei "tempi morti" (user think time) viene solo disconnessa, ma non chiusa, e riconnessa quando serve (non vado oltre, per altre info guardatevi il pattern Open Session in View). Nel caso di applicazione web è posta nella HttpSession, mentre per applicazioni desktop si usa un singleton associato al thread principale.

Bene, ora una breve descrizione del problema (più che bug) che avevo: anche se la sessione era opportunamente configuarata per non eseguire mai nulla fino ad un Commit esplicito (e "accumulare" però le modifiche rischieste), debuggando passo passo mi accorgevo che questo non sempre accadeva, e in particolare quando vi erano richieste business di creazione di nuovi oggetti. Nota: l'impostazione di cui parlo è la proprietà FlushMode della sessione settata a FlushMode.Never, che permette di "rinviare" il commit fino alla richiesta esplicita con session.Flush().

Ok, e ora la soluzione al problema (ovviamente!): lasciate stare il vostro DAL così com'è, non toccatelo, è già a posto... il problema è nel file di mappatura delle classi. Quindi andate dallo sviluppatore che si occupa delle classi del dominio e della gestione della mappatura con il database (nel mio caso, me stesso! quindi non posso arrabbiarmi troppo!) e chiedetegli di verificare quale strategia di generazione degli ID si stà utilizzando. Infatti, nel mio caso avevo scelto la strategia native, così da rendermi ancora più indipendente dal DB (certo che non ci si accontenta mai!), visto che testo su MSSQL e MySQL. Il fatto è che questa strategia non fa che "demandare" a NHibernate la scelta più appropriata tra quelle disponibili sul DB scelto (identity, sequence o hilo), e queste (correggetemi se sbaglio) sono tutte strategie di generazione che richiedono accesso al DB (come per incrementare l'ultimo valore creato, etc...). E quindi in questa fase avviene così anche la creazione dei nuovi oggetti, poichè (mi pare di aver capito) non è possibile incrementare un indice per le identità senza creare il record corrispondente. Sicuramente quest'ultima non è del tutto corretta, e non vuole esserlo: mi basta aver individuato il problema, e anche la soluzione.

"Basta" (quando possibile, immagino) cambiare strategia e usarne una "applicativa" invece che demandarla al DB. Quelle possibili sono uuid.hex, uuid.string, guid, guid.comb e assigned. L'elenco completo con una descrizione si trova al paragrafo sui generatori di id nella documentazione di NHIbernate. Nel mio caso quindi, oltre che cambiare il file di mappatura, ho anche dovuto mettere mano agli oggetti del dominio e convertire tutti i campi id da interi a stringhe.

Per altre info, vi lascio questo link: è un post sul forum di Hibernate in cui si parla dello stesso mio problema.

Ora tutto bene, ho potuto eliminare questa issue dalla lista, e ributtarmi a capofitto sulle altre!

Buon lavoro a tutti.
ciao
-papo-

Print | posted on mercoledì 10 maggio 2006 16:37 | Filed Under [ .NET ]

Powered by:
Powered By Subtext Powered By ASP.NET