NHibernate: Session e Lazy Loading

Più volte mi è stata posta questa domanda che qui riassumo:

NHibernate nell'ambito di una session può caricare oggetti le cui collezioni vengono marcate come lazy. Gli oggetti delle collezioni non verranno caricati se non in seguito al richiamo della prima funzione che ne fa uso (Un count, il richiamo di un item e così via), il tutto mediante l'uso di un trasparente di un proxy.
Fin qui tutto bene.
I problemi iniziano quando un oggetto caricato (non completamente) in una session viene passato ad un altra session magari perchè appartenente ad una transazione applicativa (transazioni lunghe che hanno uno span su più transazioni di database), o magari all'interno di una applicazione ASP.NET dove viene passato tra una richiesta ed un'altra.
Nella seconda session, al tentativo di inizializzare le collezioni marcate come lazy si ottiene una LazyInitializationException.
Perchè? [Urla indistinte del programmatore di turno]
Non potrebbe NHibernate (in maniera nascosta all'utente) fare tutto il lavoro sporco e completarsi il lavoro di inizializzazione?

La risposta è:
Potrebbe ma introdurrebbe più problemi che soluzioni, poichè ci sarebbero gravi conseguenze sull'accesso transazionale.

Mi spiego:
Ammettiamo che nella prima sessione si utilizzi una transaction demarcation (si faccia partire una nuova transazione) che sta ovviamente su una propria connessione; se nella successiva session si dovesse inizializzare la parte lazy si dovrebbe far partire una nuova connessione, perdendo coerenza e fuoriuscendo dalla demarcazione della prima transazione.

Il fatto è che non bisogna considerare NHibernate (in particolare l'oggetto session) come un mero servizio di richiesta/persistenza di entità da un database, al di fuori da contesti di Unit of Work,
Nhibernate è un servizio di on line transaction processing e come tale deve offrire una propria demarcazione transazionale nelle operazioni di persistenza.

E allora, come risolviamo?:
La soluzione è ovviamente pensare ad un giusto disegno applicativo e ad una corretta demarcazione delle unit of work:

Ecco una semplicissima strategia:
..
obj = session1.Get(typeof(MiaClasse), id);
// lavoro su obj
session.Flush();

// Passo obj ad una nuova session

session2.Update(obj);
// oppure session2.Lock(obj, LockMode.Read);
// lavoro su obj dove eventualmente può essere inizializzata la parte lazy dell'oggetto
session2.Flush();

L'update sulla seconda session è solo schedulato e non eseguito grazie al Transparent Write Behind.

Print | posted on giovedì 5 gennaio 2006 14.54

Feedback

# re: NHibernate: Session e Lazy Loading

left by Krios at 05/01/2006 15.21 Gravatar
Ti devo la vita.. ma forse ti accontenti di una pizza :P

# Come mi piace implementare il Lazy Load con un pizzico di polimorfismo...

left by Web Log di M.rkino at 05/01/2006 17.34 Gravatar
Ogni layer pu

# Come mi piace implementare il Lazy Load con un pizzico di polimorfismo...

left by Web Log di M.rkino at 05/01/2006 17.36 Gravatar
Ogni layer pu

# re: NHibernate: Session e Lazy Loading

left by theEvil at 06/01/2006 2.55 Gravatar
Cosa succede esattamente in questo modo ?
Perchè richiami subito session2.Update(obj) ?

Grazie 1000.

# re: NHibernate: Session e Lazy Loading

left by Giancarlo Sudano at 10/01/2006 12.46 Gravatar
per theEvil:

richiamando subito un update (o un lock) l'oggetto che prima era nello stato di detached passa di nuovo allo stato di persistent, e verrà sincronizzato verso il db.

# re: NHibernate: Session e Lazy Loading

left by Antonio at 06/10/2007 23.58 Gravatar
Se io avessi il code-behind di una webform che deve popolare un repeater con una collezione di oggetti figli dell'oggetto preso dal viestate, come farei a fare il lock? Non sarebbe giusto farlo da bl? scusa il ritardo
Comments have been closed on this topic.