Durante una "chattata" con Marco di più di un mese fa, gli dissi che non concordavo con la metodologia da lui illustratami di creare una Session per ogni nuovo Form (Win o Web poco cambia) perchè non mi va assolutamente di "legare" in alcun modo la UI con i livelli sottostanti, ne l'idea di un BizLayer non "stateless".
Tuttavia qualche settimana dopo, con molto più tempo e più calma a disposizione, al Mastering di Janky ho avuto la possibilità di comprendere quanto sia necessario gestire e mantenere il più possibile "vivo" il contesto di persistenza (la Session, nel caso di NHibernate), ma neanche la soluzione ipotizzata durante la chiacchierata post corso con Janky mi aveva convinto.
Fortunatamente di natura ho un BackgroundProcess (WAPR per gli amici) che continua a ruminare le cose che non "quadrano" come vorrei ma che reputo importanti e mumble e rimumble ho abbozzato una possibilità con qualche piccola variante "capra&cavoli" che via via ha preso sempre più piede nella mia testa e che sto utilizzando da qualche giorno in un nuovo piccolo software capitato proprio a fagiolo...
Intendiamoci: niente di innovativo, sicuramente un sacco di gente sarà già passata da queste scaramucce anni fa, ma la voglio riportare come una delle mie piccole milestones.
In sostanza:
- Il contesto di persistenza serve (NHibernate o non NHibernate) e sia le UOW che l'Identity Map devono ovviamente "sopravvivere" oltre la singola chiamata "verticale".
- Le entità devono continuare a rimanere "anemiche".
- Il BizLayer, soprattutto in un'ottica SOA, deve IMHO essere il più possibile stateless e presentare funzioni statiche al livello superiore.
La soluzione è banale come la calza di una coccinella: utilizzare una semplice interfaccia (vuota, nel mio caso) IPersistenceContext (lo so, lo so... ho poca fantasia...) come semplice segnaposto per far viaggiare tra i vari layers il contesto di persistenza.
In sostanza:
- Ho quindi definito un'interfaccia IPersistenceContext che implementa IDisposable ma non contiene membri (so che fa storcere il naso ma ha un suo "perchè") ed è contenuta in un assembly separato (comune a tutti i progetti) che viene referenziato da tutti i layers.
- I metodi del BizLayer sono rimasti statici ma si sono "arricchiti" del paramento IPersistenceContext
(es. public static Employee GetEmployee(Guid employeeId, IPersistenceContext persistenceContext) - Il BizLayer ha un metodo Factory per il PersistenceContext concreto che in realtà richiama l'analoga factory nel DAL concreto. Nel caso di un DAL che sfrutta NHibernate, per esempio, verrà restituito un nuovo NhPersistenceContext che la UI conserverà e riutilizzerà ad ogni chiamata fino alla Dispose.
- Solo il DAL conosce il tipo di PersistenceContext utilizzato (d'altronde è stato lui a fornirlo!) e gli altri layers se ne lavano allegramente le mani, risultando assolutamente svincolati dall'implementazione utilizzata (per esempio la Session di NH o il contesto di persistenza di un altro ORM o un contesto di persistenza implementato a manina o addirittura un contesto di persistenza... non implementato!).
I sostanza, mi sembra che così si riesca a far felice l'ORM, senza "intaccare" il DDD!
Il tutto chiaramente grazie alla pazienza di Marco e Janky nel sopportare le mie perplessità... :-)