Crad's .NET Blog

L'UGIblog di Marco De Sanctis
posts - 190, comments - 435, trackbacks - 70

La Unit of Work e le Web Apps

Ieri Imperugo di ASPItalia ha pubblicato un post a proposito di NHibernate sul suo blog e ne è seguita una discussione parecchio interessante con nostromo, Daniele e ricky, proseguita con quest'ultimo anche su MSN.

Un passo di tutto questo disquisire era qualcosa del tipo: "ha senso una Unit of Work in una Web Application, in cui il codice lato server è solitamente stateless?"

Secondo Riccardo "una UoW ha il compito di creare un contesto transazionale a livello di logica applicativa, cosa che nel web per motivi prestazionali è preferibile fare in altri modi" e quindi scegliere se utilizzarla o meno dipende dai casi; ma dopo essermi confrontato anche con Janky e alla luce della mia esperienza (che comunque non è paragonabile a quella dei miei interlocutori), io sono convinto del contrario.

L'esempio è quello di una qualsiasi relazione Master-Detail; pensiamo di avere un ipotetico oggetto di tipo Fattura, recuperato in qualche modo dal DB. Tale oggetto ha una collection di DettaglioFattura e ogni Dettaglio ha la sua bella reference alla fattura stessa. In pratica:

Ora, supponiamo di andare a modificare la composizione delle righe, perché eliminamo un dettaglio. Io, nel mio codice, voglio limitarmi a scrivere qualcosa di tipo

miaFattura.Details.RemoveAt(3);
provider.Persist(miaFattura);

Se ci pensiamo, non è banale fare in modo che questo codice funzioni, perché non faccio nessuna chiamata ad un DAL per il mio dettaglio, che è ancora lì in memoria e punta ancora alla mia fattura. Ma la Unit of Work si accorge che la composizione del dettaglio è cambiata e genera una query di DELETE sul DB per quella riga che è stata rimossa.

UPDATE: Ho scritto una cosa errata, interpretando male il pensiero di Riccardo: egli non dice che NON abbia senso una UoW in uno scenario Web, ma che NON HA SENSO SEMPRE. Mi scuso con il diretto interessato per aver travisato la sua idea.

powered by IMHO 1.3

Print | posted on giovedì 20 luglio 2006 12.34 | Filed Under [ NHibernate Architettura ]

Feedback

Gravatar

# re: La Unit of Work e le Web Apps

Ciao Crad, come ho chiesto nel topic della discussione su NH, volevo sapere che ne pensavi di Gentle.NET e ActiveRecord

Con quest'ultimo ho problemi con la cache (anche abilitando la cache di 2 livello di NH) nel senso che ogni volta che faccio una query con risultato IList e nn una singola entità, fa la richiesta ogni volta al db, mentre con Gentle una volta fatta la query, utilizza il risultato che ha nella cache....

nn so se hai capito niente, visto che io e l italiano abbiamo litigato da piccoli :P:P:P
20/07/2006 12.40 | Carlo Bertini
Gravatar

# Re: La Unit of Work e le Web Apps

Certo che questi diagrammini sono proprio professionali!!!
20/07/2006 13.03 | Simone Chiaretta
Gravatar

# Re: La Unit of Work e le Web Apps

Voterei Marco ClassDesigner MVP
20/07/2006 13.06 | Simone Chiaretta
Gravatar

# Re: La Unit of Work e le Web Apps

Ciao Marco, potresti dettagliare un po' meglio il "perchè si" all'utilizzo di Unit of Work in una Web app, e qual'è il modo più efficiente di implementarlo e quindi di persistere lo stato?
20/07/2006 13.13 | Lorenzo Melato
Gravatar

# re: La Unit of Work e le Web Apps

ciao marco, aggiungo a quanto abbiamo detto su aspitalia che personalmente nella implementazione del Dal che utilizzo faccio uso della UnitOfWork,solo che a differenza di

miaFattura.Details.RemoveAt(3);
provider.Persist(miaFattura);

scrivo solo

miaFattura.Details.RemoveAt(3);
miaFattura.Update();

questo perchè la mia classe fattura deviverebbe da una classe che offre una serie di servizi cosa che a seconda delle necessità non fanno tutte le classi.
20/07/2006 14.07 | Nostromo
Gravatar

# re: La Unit of Work e le Web Apps

Con Simone ci siam già parlati su MSN :D

Rispondo agli altri:

@Carlo: non so cosa dirti perché non li ho mai provati, mi spiace :(

@Lorenzo: sarò veloce perché sono un po' di fretta, e me ne scuso, magari se interessa proverò ad espandere in un prossimo post.
A cosa serve la unit of work? Allora... hai una entity in memoria e vuoi persisterla. Domanda: come fai a sapere che tipo di query inviare al DB? Esiste già nella base dati una rappresentazione di quell'oggetto o è del tutto nuovo? e se è già esistente, cosa hai cambiato?

Senza UoW sei costretto a rispondere a queste domande nella tua logica di business, sei costretto a gestire in maniera differente il caso in cui tu istanzi una fattura con un bel new, o il caso in cui tu recuperi una fattura dal DB e ne vari la data, chiamando a seconda dei casi due metodi di persistenza diversi.
L'esempio che ho citato nel post, poi, è ancora più complesso: come fai a sapere che, da quando hai recuperato la fattura a quando torni a persisterla, la collection dei dettagli contiene un oggetto in meno? Sei costretto a gestire manualmente, rispondendo all'input dell'utente dal tuo BLL, l'operazione di eliminazione di un dettaglio.
La UoW tiene invece traccia di tutto quanto accade nella tua entity da quando l'hai recuperata fino a quando non torni a persisterla.

Mi chiedi un esempio di implementazione... beh, premesso che come avrai intuito, realizzare un oggetto di questo tipo è tutt'altro che banale (ed è principalmente questa la ragione che mi fa propendere per un ORM, ad es. NHibernate, che magari ce l'ha già), su PoEAA di Fowler c'è un bell'esempio di UoW realizzata a partire da un DataSet (che a sua volta, se ci pensi, implementa una sorta di UoW, dato che tiene traccia delle modifiche che avvengono nelle tabelle dal Fill fino all'Update). Per sommi capi... invece di creare direttamente l'oggetto dal resultset di un command, riempio opportunamente le tabelle di un dataset (che resta in memoria nella mia UoW) e da queste istanzio l'oggetto del mio domain.
La persitenza è realizzata rimappando l'oggetto verso le tabelle e poi chiamando l'Update del relativo DataAdapter. In questo modo posso tener traccia delle modifiche effettuate da quando ho recuperato la entity dal db o capire se questa entity è nuova, tutto grazie al RowState delle righe del mio DataSet.

La domanda è... ma essendoci tool già pronti, testati, in uso oramai da qualche anno, che mettono a disposizione tutto ciò (e molto di più), ha veramente senso farselo da soli?

Ciao!
20/07/2006 14.26 | Marco De Sanctis
Gravatar

# re: La Unit of Work e le Web Apps

Sul fatto che la Unit of Work stia sul DAL...mi puzza un pochino...è robaccia da business poichè a seconda dei casi serve da demarcatore di una transazione...e cosa mettere dentro un contesto transazionale deve essere deciso nel business layer...(immaginate un trasferimento di fondi).

Altra cosa:
Dal codice di Nostromo si evince chiaramente un pattern Layer SuperType, o volendo anche un pattern ActiveRecord che cmq non risolve il problema degli step percorsi dal codice. Chi tiene lo snapshot di come era prima la collection e come era dopo? e se uno fa una aggiunta e una cancellazione della stessa riga? cosa si passa al db?

Per vedere quanto è brillante NH da questo punto di vista sbirciate codice e slide della mia sessione su NH al meeting di Xedotnet...
20/07/2006 14.30 | Giancarlo Sudano
Gravatar

# re: La Unit of Work e le Web Apps

Altra nota su quanto detto da Ricky (riportato da questo post)....
La Unit of Work ha senso SEMPRE quando l'applicazione Web o non Web utilizza un Domain Model...
non centra niente lo stateless delle webapp....

Sarebbe da spostare sul forum questa discussione...:-)
20/07/2006 14.33 | Giancarlo Sudano
Gravatar

# Re: La Unit of Work e le Web Apps

Marco, forse mi sono spiegato male, scusa se ti ho fatto perdere tempo prezioso. So cos'è UoW. I miei dubbi si riferivano all'implementazione in una archiettura stateless come ASP.NET. La domanda esplicita é: dove tengo la sessione di NHibernate (che mi incapsula la UoW) tra una chiamata-risposta al server e l'altra? Mi verrebbe spontaneo pensare di metterla in una Session, ma quanto costa in termini di risorse e quindi di performance. E quanto mi va a inficiare sulla scalabilità dell'applicazione? Scusa se magari la mia domanda è banale ma sono un neofita di NHIb. ;-)
20/07/2006 14.33 | Lorenzo Melato
Gravatar

# re: La Unit of Work e le Web Apps

Per Marco-Nostromo:
Bene, peccato che allora se mi scrivi quel codice e quel commento, io capisca che stiamo parlando di cose diverse :)

Nelle mie applicazioni utilizzo il pattern Domain Model, in cui le entity sono semplici e si limitano a rappresentare dati. Punto. Non ho classi che offrono servizi particolari nel caso contengano relazioni con altre entity, e tantomeno hanno un metodo Update() per essere salvate su DB. E c'è qualche tonnellata di letteratura che giustifica un approccio simile.

Le tue, da quello che capisco dal tuo commento, sono invece simili a quelle illustrate da Marco Bellinaso nel suo libro (lo cito perché mi pare ne avessimo parlato in passato), quindi stiamo parlando di due mondi differenti. Occhio però, perché iniettare questo tipo di logica nel modello a oggetti può portare la tua applicazione ad essere difficilmente manutenibile e minare la riusabilità delle tue classi, che diventano application specific. Ma qui mi rendo conto che sto divagando troppo... ;)

A presto Marco, e grazie cmq di questo confronto perché credo che sia il modo migliore per imparare!
20/07/2006 14.34 | Marco De Sanctis
Gravatar

# re: La Unit of Work e le Web Apps

aggiungo un altro pezzo visto che una sola riga spiega poco, non ho detto che il Metodo Update chiama il salvatagio sul db.

o meglio in alcuni casi utilizzo un UnitOfWork in altri ho una semplice query.

ho una sorta di architettura a provider, chiamiamolo un UnitOfWorkProvider o un QueryProvider.

magari non ho semplici entity ho meglio ho anche quelle, ma anche oggeti complessi ma ne gestisco la complessità dividendo bene le competenze.

non ricordavo la discussione su Bellinaso :D, bhe anche io ti ringrazio del confronto fa sempre piacere magari sapessi spiegarmi meglio :)

ciao marco

20/07/2006 15.44 | Nostromo
Gravatar

# re: La Unit of Work e le Web Apps

Per Lorenzo:
scusa ma son stato impegnato da un cliente. In realtà (e ringrazio anche janky per la consulenza) una best practice per utilizzare NH su ASP.NET è costruire un opportuno httpModule che istanzi una session ad ogni webRequest, come descritto qui

http://www.codeproject.com/aspnet/NHibernateBestPractices.asp

Premetto che ancora non faccio uno stress test (e mi riprometto di farlo), ma AFAIK la costruzione di una session per request dovrebbe essere abbastanza innocua, sia in termini di impiego di risorse, che in termini temporali.

Ripeto, non ho numeri alla mano, quindi prendi tutto ciò che dico con le molle. Però ho letto parecchi post in cui si afferma che questo sia il modo migliore per lavorare sulle entities in maniera del tutto trasparente e con un impatto prestazionale trascurabile.
20/07/2006 20.57 | Marco De Sanctis
Gravatar

# Re: La Unit of Work e le Web Apps

Grazie Marco, è quello che speravo di sentirmi dire! :-)
21/07/2006 9.45 | Lorenzo Melato
Gravatar

# re: La Unit of Work e le Web Apps

Ciao a tutti, mi intrometto nella discussione riprendendo il post di marco in cui parla della best practice per l'utilizzo di NH in ASP.NET

Sto usando anchio l'HTTP module descritto in questo esempio per ottenere una transaction che parte con la web request e di cui viene eseguito il commit alla fine della richiesta.

In questo modo, tutte le modifiche apportate alle mia entity vengono automaticamente salvate su db ad ogni postback.
Questo approccio mi spiazza un poco in quanto io sono abituato a mantenere gli oggetti modificati nella session asp.net e solo quando l'utente conferma le modifiche persisto quest'ultime sul db.

Dato che sono un neofita di NH e non ho la vostra esperienza di sviluppo in ASP.NET vi chiedo è corretta la strada indicata dalla best practice di cui sopra oppure se può aver senso il mio tentativo di "nascondere" la natura stateless tipica delle applicazioni web?
24/07/2006 15.44 | Giorgio Parmeggiani
Gravatar

# re: Tu chiamale, se vuoi... Riflessioooniiiiii

Gravatar

# re: La Unit of Work e le Web Apps

capisco che sono arrivato tardi su questo post....ma visto che ci sono (e che sono un novizio di NH) vi chiedo un chiarimento.

Io sono abituato a costruire le mie Web App suddivise in 4 progetti .NET

1) Entities (senza logica alcuna...solo un pò di polimorfismo)
2) DAL (se il mio può chiamare così)
astratto e solo per accesso ai dati su DB
3) BLL
Tutte le classi che mi permetto di mandare e ricere informazioni al DAL e di effettuare le validazioni e composizioni degli oggetti....in più qualche volta implementa semplici UoW
4) UI
mi interfaccio con la BLL per tutto e lavoro con le mie Entities.....e non conosco niente il DAL

Con NH invece (sicuramente ho capito male) il progetto DAL e BLL sono la stessa cosa in quanto NH mi permette di persistere i dati su DB e utilizzare Interceptor per eventuali validazioni e/o gestioni di business....mentre la UoW è di conseguenza al disegno delle entities

Lo so che fa molto di più, ma la mia domanda, o meglio le mie domande sono:

1) come dividete i progetti in fase di creazione?

2) Se voglio mantenere la sessione di NH aperta per utilizzare tutti i suoi benefici, devo per forza utilizzare dei riferimenti ad Nhibernate nelle mi Web App.....non causo così un grande accoppiamento tra interfaccia e accesso ai dati?

3) Sono d'accordo che posso evitarlo esponendo interfacce....ma a questo punto non mi perdo il lazy loading?
23/03/2007 19.26 | Simone
Gravatar

# re: La Unit of Work e le Web Apps

Ciao ragazzi, interessante discussione, ma alla fine, qual e' il succo del discorso?. si e' parlato di httpmodule, UoW, e altro. ma qual e' l'approccio migliore.
io sto usando nh in un app web, uso un approccio architetturale non domain model e cio non ho entity.update ma bensi provider.update(entity). Come qualcuno di voi. Ma essendo un applicativo web mi perdo lo stato della sessione. Mi sapete dire se c'e' un documento o altro da usare come riferimento per Nhibernate con questo tipo di approccio. Anche io come altri ho problemi nella cancellazione di un elemento della lista dettagli.
02/07/2008 11.21 | giovanni

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 3 and 8 and type the answer here:

Powered by: