2010-04-26 7 views
13

Ho passato il resto della serata a leggere le domande StackOverflow e anche alcuni blog e link sull'argomento. Tutti si sono rivelati molto utili, ma sento ancora che in realtà non rispondono alla mia domanda.Un repository statico è un modo giusto per utilizzare NHibernate?

Quindi, sto sviluppando una semplice applicazione web. Mi piacerebbe creare uno strato di accesso ai dati riutilizzabile che potrò poi riutilizzare in altre soluzioni. Il 99% di queste saranno applicazioni web. Questa sembra essere una buona scusa per imparare l'NHibernate e alcuni degli schemi attorno ad esso.

I miei obiettivi sono i seguenti:

  • Non voglio lo strato di logica di business di sapere nulla circa il funzionamento interno del database, né NHibernate stesso.
  • Desidero che il livello della logica aziendale abbia il minor numero possibile di presupposti sul livello di accesso ai dati.
  • Desidero che il livello di accesso ai dati sia il più semplice e intuitivo possibile. Questo sarà un progetto semplice, quindi non voglio complicare eccessivamente nulla.
  • Desidero che il livello di accesso ai dati sia il più possibile non intrusivo.

Considerando tutto ciò, ho deciso di utilizzare il famoso modello di repository. Ho letto di questo argomento su questo sito e su vari blog di sviluppo e ho sentito alcune cose sul modello dell'unità di lavoro.

Mi sono anche guardato intorno e controllato varie implementazioni. (Includendo FubuMVC contrib e SharpArchitecture e cose su alcuni blog). Ho scoperto che la maggior parte di questi operano con lo stesso principio: creano una "unità di lavoro" che viene istanziata quando un repository viene istanziato, iniziano una transazione, fare cose, e commettere, e quindi ricominciare tutto da capo. Quindi, solo uno ISession per Repository e il gioco è fatto. Quindi il codice client deve istanziare un repository, fare cose con esso e poi smaltirlo.

Questo schema di utilizzo non soddisfa il mio bisogno di essere il più semplice possibile, quindi ho iniziato a pensare a qualcos'altro.

Ho scoperto che NHibernate ha già qualcosa che rende superflue le implementazioni di "unità di lavoro" personalizzate e che è la classe CurrentSessionContext. Se configuro il contesto della sessione correttamente e pulisco quando necessario, sono a posto.

Quindi, mi si avvicinò con questo:

Ho un classe statica interno chiamato NHibernateHelper. In primo luogo, ha una proprietà statica chiamata CurrentSessionFactory, che al primo richiamo crea un'istanza di una sessione e la memorizza in un campo statico. (Uno ISessionFactory per uno AppDomain è abbastanza buono.) Quindi, ancora più importante, ha una proprietà statica CurrentSession, che controlla se c'è un ISession legato al contesto di sessione corrente, e in caso contrario, crea uno e lo lega, e ritorna con il ISession associato al contesto di sessione corrente.

Poiché sarà utilizzato principalmente con WebSessionContext (così, uno per ogni ISessionHttpRequest, anche se per i test di unità, ho configurato ThreadStaticSessionContext), dovrebbe funzionare senza problemi. E dopo aver creato e vincolato un ISession, associa un gestore di eventi all'evento HttpContext.Current.ApplicationInstance.EndRequest, che si occupa della pulizia dello ISession al termine della richiesta.(Naturalmente lo fa solo se è veramente in esecuzione in un ambiente web.)

Quindi, con tutto questo impostato, il NHibernateHelper sarà sempre in grado di restituire un valore valido ISession, quindi non è necessario istanziare un'istanza di repository per "unità di lavoro" per funzionare correttamente. Invece, Repository è una classe statica che funziona con ISession dalla proprietà NHibernateHelper.CurrentSession e espone le funzionalità tramite metodi generici.

Quindi, sostanzialmente, ho finito con due singleton molto pigri.

Sono curioso, cosa ne pensi di questo? È un modo valido di pensare, o sono completamente fuori strada qui?

EDIT:
mi preme ricordare che la classe NHibernateHelper è interna, quindi praticamente invisibile ai consumatori del repository.

Un'altra idea è, per creare un'iniezione di dipendenza nella soluzione, è creare un'interfaccia denominata IDataProvider e creare un'istanza di quella alla prima chiamata alla classe Repository. (Tuttavia, il codice di attuazione dovrebbe essere in grado di prendersi cura del concetto di contesto anche.)

EDIT 2:
Sembra che molte persone come la mia idea, ma ci sono ancora troppo poche opinioni su di esso nel risposte.
Posso supporre che questo sia un modo giusto per utilizzare NHibernate, quindi? : P

risposta

2

Per quello che vale, Sharp Architecture sta facendo più o meno esattamente quello che stai suggerendo. Finisce consegnando una sessione per richiesta HTTP (più precisamente, una sessione per database per richiesta HTTP). Il tuo approccio è certamente valido e offre anche una sessione per richiesta. Preferisco piuttosto l'approccio OO più pulito di SharpArch tramite DI oltre l'utilizzo di repository statici e la classe helper.

+0

Ebbene sì, ma penso che la mia soluzione abbia una sintassi un po 'più facile da usare e sicuramente meno overhead in termini di istanziazione degli oggetti e, quindi, utilizzo della memoria. – Venemo

1

Abbiamo mescolato applicazioni ASP.NET/Windows Form e la soluzione migliore che ho trovato è quella di fare l'iniezione manuale delle dipendenze attraverso il costruttore del repository. Cioè, ogni classe di repository ha un singolo costruttore pubblico che richiede una ISession. Ciò consente all'applicazione di avere il controllo completo sui confini dell'unità di lavoro e delle transazioni. È semplice ed efficace Ho anche un assembly helper NHibernate molto piccolo che configura le factory di sessione e fornisce metodi per aprire una sessione regolare o di contesto.

Ci sono un sacco di cose che mi piacciono nell'architettura di S # arp e penso che valga la pena studiare come funziona, ma l'ho trovato troppo architettato per i miei gusti.

+0

+1, l'ho trovato anche troppo architettato. Tuttavia, un repository statico è ancora più semplice, ecco perché penso che sia la strada da percorrere. – Venemo