2010-05-28 16 views
6

Ho una webapp che si collega a 2 DB (un core, l'altro è un DB di registrazione).Multiple SessionFactories in Windows Service con NHibernate

Ora devo creare un servizio di Windows che utilizzerà la stessa logica di business/DLL di accesso ai dati. Tuttavia, quando provo a fare riferimento a 2 factory di sessione nell'app del servizio e a chiamare il metodo factory.GetCurrentSession(), viene visualizzato il messaggio di errore "Nessuna sessione è legata al contesto corrente".

Qualcuno ha un suggerimento su come questo può essere fatto?

public class StaticSessionManager 
{ 
    public static readonly ISessionFactory SessionFactory; 
    public static readonly ISessionFactory LoggingSessionFactory; 

    static StaticSessionManager() 
    { 
     string fileName = System.Configuration.ConfigurationSettings.AppSettings["DefaultNHihbernateConfigFile"]; 
     string executingPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase); 
     fileName = executingPath + "\\" + fileName; 
     SessionFactory = cfg.Configure(fileName).BuildSessionFactory(); 

     cfg = new Configuration(); 
     fileName = System.Configuration.ConfigurationSettings.AppSettings["LoggingNHihbernateConfigFile"]; 
     fileName = executingPath + "\\" + fileName; 
     LoggingSessionFactory = cfg.Configure(fileName).BuildSessionFactory(); 
    } 
} 

Il file di configurazione è l'impostazione:

<property name="current_session_context_class">call</property> 

Il servizio imposta le fabbriche:

private ISession _session = null; 
private ISession _loggingSession = null; 
private ISessionFactory _sessionFactory = StaticSessionManager.SessionFactory; 
private ISessionFactory _loggingSessionFactory = StaticSessionManager.LoggingSessionFactory; 

... 

_sessionFactory = StaticSessionManager.SessionFactory; 
_loggingSessionFactory = StaticSessionManager.LoggingSessionFactory; 

_session = _sessionFactory.OpenSession(); 
NHibernate.Context.CurrentSessionContext.Bind(_session); 
_loggingSession = _loggingSessionFactory.OpenSession(); 
NHibernate.Context.CurrentSessionContext.Bind(_loggingSession); 

Così alla fine, provo a chiamare il corretto fabbrica da:

ISession session = StaticSessionManager.SessionFactory.GetCurrentSession(); 

Qualcuno può suggerire un modo migliore per gestire questo?
Grazie in anticipo!
Rob

+0

La tua domanda ha risolto la mia domanda :) Grazie. – SadullahCeran

risposta

4

La prima cosa che posso suggerire è di rendere entrambe le istanze ISessionFactory come statiche. Questi dovrebbero essere singleton in quanto sono molto costosi da istanziare.

EDIT # 1

Consiglieresti creo le sedute quando ne ho bisogno, o lasciarle aperte?

L'API ISession gestisce la connessione internamente. Dopo un po ', se non viene richiesta alcuna interazione con il database sottostante, la connessione viene chiusa, anche se il tuo ISession mantiene la sua istanza di connessione. Una volta che ha bisogno di eseguire alcune altre transazioni con il database, riapre la connessione precedentemente utilizzata.

Per rispondere alla tua domanda, l'approccio preferito è un'istanza dell'API ISession per pagina (Web) o per modulo (desktop). Ad esempio, consideriamo di avere un software di contabilità e l'utente ha una gestione da fare sui clienti. Quindi, quando carichi il tuo CustomerMgmtForm, dovresti fornire un'istanza di ISession in modo che possa caricare i tuoi clienti, tenere traccia delle modifiche, cancellazioni e nuovi clienti creati (una volta uniti allo ISession, in modo che quando si chiama il metodo SaveOrUpdate(), il ISession sa che cosa ha a che fare con le modifiche rilevate e le entità transitori.

Perché un'istanza per pagina o per forma, ti chiedi?

Dal momento che l'API ISession tiene traccia di ogni modifica che si verificano a un oggetto, immagina una volta che hai caricato i tuoi clienti, fornitori e alcuni altre entità devi prenderti cura della tua applicazione. Ognuna delle modifiche eseguite sui clienti, non ha alcun diritto sui fornitori. Ma questi clienti saranno ancora lì, perché è l'istanza di ISession che hai usato per i tuoi clienti!Quindi, i requisiti dell'applicazione per la memoria aumentano con la quantità di oggetti caricati. Inoltre, è noto che quando lo ISession diventa troppo grande in memoria, potrebbe causare alcune perdite di memoria, quindi considerare come non più sessione valida da parte di NHibernate, scartando tutte le modifiche non salvate e tutto, come la sessione che monitorava le tue entità ora non è valido.

In aggiunta ad esso, quando si apre diciamo che il CustomerMgmtForm, si dovrà gestire clienti entità. È più probabile che tu non debba tenere traccia dei tuoi clienti una volta chiuso il modulo o che abbia anche aperto il SuppliersMgmtForm, all'interno del quale dovrai gestire i tuoi fornitori. In questo modo, avrai due istanze dell'API ISession: La prima - customerMgmtSession, l'altra - suppliersMgmtSession. Quindi, non dovrebbero mai diventare troppo grandi per venire a causare una perdita di memoria, in quanto entrambi hanno le proprie entità da gestire o da curare. Entrambi sono totalmente indipendenti l'uno dall'altro.

Seguendo questo approccio, è necessario chiudere e smaltire l'istanza di ISession API su FormClosing evento per Windows Form, o qualsiasi altra cosa equivalente in Web. Così ora, in un servizio di Windows, è per te decidere qual è la situazione ideale e decidere dove sarebbe più appropriato per le tue esigenze, a seconda di cosa fa il tuo servizio.

Una cosa però, se il tuo servizio non richiede di tenere traccia delle tue modifiche o di qualsiasi tipo sulle tue entità, l'API IStatelessSession è forse più appropriata da usare. Usandolo, di sicuro suggerisco di aprire o creare un'istanza di una sessione senza stato solo quando è necessario interagire con il database sottostante, poiché non è possibile mantenere lo stato IStatelessSession in quanto non fornisce le risorse da mantenere qualsiasi traccia relativa alle modifiche apportate alle entità. Questo è il maggiore e solo per errore, se ricordo bene, la differenza tra le API ISession e IStatelessSession.

EDIT # 2

In questo modo, come sopra citato nel mio EDIT # 1, potrebbe anche aiutare a risolvere il problema, in quanto non sarebbe mai bisogno di chiamare ISessionFactory.GetCurrentSession().

Spero che questo aiuti! =)

+0

Buon punto - L'ho cambiato ora, anche se lavoro sul presupposto che creo le fabbriche solo una volta. Consiglieresti di creare le sessioni quando ne ho bisogno o di lasciarle aperte? –

+0

Per favore vedi il mio ** EDIT # 1 ** per la tua risposta alla tua domanda posta nel commento. =) –

+0

Questa è una grande spiegazione, grazie per aver dedicato del tempo! Ne parlerò ora con un paio di colleghi e vedremo se è necessario apportare alcune modifiche al codice in modo che possiamo farlo funzionare su entrambe le piattaforme. Grazie ancora! –