2010-05-28 10 views
6

Tengo una aplicación web que se conecta a 2 bases de datos (un núcleo, el otro es una base de datos de registro).Multiple SessionFactories in Windows Service con NHibernate

Ahora debo crear un servicio de Windows que utilizará la misma lógica comercial/DLL de acceso a datos. Sin embargo, cuando intento hacer referencia a 2 fábricas de sesión en la Aplicación de servicio y llamar al método factory.GetCurrentSession(), aparece el mensaje de error "No hay sesión vinculada al contexto actual".

¿Alguien tiene alguna sugerencia acerca de cómo se puede hacer esto?

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(); 
    } 
} 

El archivo de configuración tiene la configuración:

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

El servicio establece las fábricas:

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); 

Así que, finalmente, trato de llamar a la fábrica correcta por:

ISession session = StaticSessionManager.SessionFactory.GetCurrentSession(); 

¿Alguien puede sugerir ab? ¿Qué manera de manejar esto?
¡Gracias de antemano!
Rob

+0

Tu pregunta ha resuelto mi pregunta :) Thx. – SadullahCeran

Respuesta

4

Lo primero que puedo sugerir es que las instancias de ambos ISessionFactory sean estáticas. Estos deberían ser únicos, ya que son muy caros de instanciar.

editar # 1

¿Recomendado puedo crear las sesiones cuando los necesito, o dejarlos abiertos?

La API ISession maneja su conexión internamente. Después de un tiempo, si no se solicita ninguna interacción con la base de datos subyacente, la conexión se cierra, aunque su ISession mantiene su instancia de conexión. Una vez que necesita realizar algunas otras transacciones con la base de datos, luego vuelve a abrir la conexión utilizada anteriormente.

Para responder a su pregunta, el enfoque preferido es una instancia de ISession API por página (web) o por formulario (escritorio). Por ejemplo, consideremos que tiene un software de contabilidad, y el usuario tiene algo de administración sobre los clientes a hacer. Luego, cuando cargue su CustomerMgmtForm, debe proporcionar una instancia de ISession para que pueda cargar a sus clientes, rastrear sus cambios, eliminaciones y los nuevos clientes creados (una vez que se unió al ISession, de modo que cuando llame al método SaveOrUpdate(), ISession sabe lo que tiene que ver con los cambios realizados y entidades transitorias.

por qué una instancia por página o por la forma, ¿se pregunta?

Desde la API ISession realiza un seguimiento de cada cambios que ocurren a un objeto, imagine una vez que haya cargado a sus clientes, proveedores y algunos otras entidades que debe cuidar en su aplicación. Cada uno de los cambios realizados sobre los clientes no tienen derecho sobre los proveedores. ¡Pero estos clientes todavía estarán allí, porque es la instancia de ISession que ha utilizado para sus clientes!Luego, los requisitos de la aplicación para la memoria aumentan con la cantidad de objetos cargados. Además, es un problema conocido que cuando ISession crece demasiado grande en la memoria, puede causar algunas pérdidas de memoria, luego NHibernate considera que no hay más sesión válida, eliminando todos los cambios no guardados y todo, como la sesión que rastreó sus entidades ahora no es válido

Además de ello, cuando se abre digamos que el CustomerMgmtForm, que tendrá que gestionar al cliente entidades. Es más probable que no tenga que hacer un seguimiento de sus clientes una vez que haya cerrado el formulario, o incluso haya abierto el SuppliersMgmtForm, dentro del cual deberá gestionar sus proveedores. Al hacerlo, tendrá dos instancias de la API ISession: la primera - customerMgmtSession, la otra - suppliersMgmtSession. Por lo tanto, nunca deberían crecer demasiado para provocar una pérdida de memoria, ya que ambos tienen sus propias entidades para manejar o cuidar. Ambos son totalmente independientes el uno del otro.

Siguiendo este enfoque, debe cerrar y disponer de la instancia de ISession API en FormClosing caso para Windows Forms, o lo que sea equivalente en Web. Entonces, ahora, en un Servicio de Windows, es usted quien debe decidir cuál es la situación ideal y decidir dónde sería la más adecuada para sus necesidades, dependiendo de lo que haga su servicio.

Una cosa, sin embargo, si su servicio no requiere mantener ningún rastro de sus cambios o sobre sus entidades, la API IStatelessSession es quizás más apropiada para su uso. Al usarlo, le sugiero que abra o instancia una sesión sin estado solo cuando necesite interactuar con la base de datos subyacente, ya que no sirve de nada mantener guardado el IStatelessSession, ya que no proporciona los recursos para mantener. cualquier rastro sobre los cambios realizados en sus entidades. Esta es la principal y quizás la única diferencia, si no recuerdo mal, la diferencia entre las API ISession y IStatelessSession.

editar # 2

Si lo hace, como se ha mencionado en mi editar # 1, también podría ayudar a resolver su problema, ya que no sería nunca tenga que llamar ISessionFactory.GetCurrentSession().

Espero que esto ayude! =)

+0

Buen punto - He cambiado eso ahora, aunque trabajo asumiendo que solo creo las fábricas una vez. ¿Me recomendaría que creara las sesiones cuando las necesite o las deje abiertas? –

+0

Por favor vea mi ** EDIT No. 1 ** para su respuesta a su pregunta en el comentario. =) –

+0

¡Es una gran explicación, gracias por tomarse el tiempo! Discutiré esto ahora con un par de colegas y veremos si tenemos que hacer algunos cambios al código para que podamos hacerlo funcionar en ambas plataformas. ¡Gracias de nuevo! –

Cuestiones relacionadas