La mayoría de los amigos que usan NHibernate para el desarrollo web conocen el modo Sesión por solicitud, pero no hay muchos ejemplos de cómo usarlo correctamente en Internet. Muchos artículos en Internet, incluso en el jardín, han cometido el mismo error. y este error se ha ido extendiendo...
Primero veamos un artículo de Flyear en el jardín, "Implementación simple de una sesión por solicitud de NHibernate".
No hay nada de malo en configurar NHibernate primero:
<nombre de propiedad='current_session_context_class'>web</property>
El error está en la clase NHinbernateSessionFactory (todos los nombres de las clases son incorrectos). NHinbernateSessionFactory.GetCurrentSession no debería incluir operaciones en HttpContext. En realidad, debería ser muy simple. Consulte (el nombre de la clase se cambió a NHibernateHelper, breve):
clase pública sellada NHibernateHelper
{
ISessionFactory pública estática de solo lectura SessionFactory;
estáticoNHibernateHelper()
{
SessionFactory = nueva configuración()
.Configurar()
.AddAssembly(/**/)
.BuildSessionFactory();
}
ISession estática pública GetCurrentSession()
{
devolver SessionFactory.GetCurrentSession();
}
}
Configure current_session_context_class como web y NHibernate generará una instancia de la clase NHibernate.Context.WebSessionContext durante la inicialización. El código fuente de la clase WebSessionContext es el siguiente:
[Serializable]
clase pública WebSessionContext: MapBasedSessionContext
{
//Campos
cadena constante privada SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";
// Métodos
WebSessionContext público (fábrica ISessionFactoryImplementor): base (fábrica)
{ }
anulación protegida IDictionary GetMap()
{
retorno (HttpContext.Current.Items[SessionFactoryMapKey] como IDictionary);
}
anulación protegida void SetMap (valor de IDictionary)
{
HttpContext.Current.Items[SessionFactoryMapKey] = valor;
}
}
WebSessionContext implementa el modo Session-Per-Request, que encapsula HttpContext, por lo que no necesitamos operar HttpContext en nuestra clase auxiliar (NHibernateSessionFactory o NHibernateHelper).
Solo necesitamos obtener la sesión de la instancia de WebSessionContext. Obtener la ISession actual de la clase WebSessionContext es bastante simple, porque WebSessionContext implementa la interfaz ICurrentSessionContext:
interfaz pública ICurrentSessionContext
{
ISession Sesión actual();
}
Clases e interfaces en el espacio de nombres NHibernate.Context
(Nota: current_session_context_class también se puede configurar como Managed_web, Call, thread_static, correspondientes a las clases ManagedWebSessionContext, CallSessionContext y ThreadStaticSessionContext respectivamente)
En el uso real, no necesitamos llamar directamente al método CurrentSession () de WebSessionContext, porque ISessionFactory proporciona un método más simple que nos permite obtener la sesión en un solo paso:
interfaz pública ISessionFactory: IDisposable
{
ISession GetCurrentSession();
//......
}
Analicemos la implementación específica del método ISessionFactory.GetCurrentSession:
El método Configuration.BuildSessionFactory en realidad devuelve una instancia de la clase SessionFactoryImpl. Echemos un vistazo breve a parte del código de SessionFactoryImpl:
1 clase pública sellada SessionFactoryImpl
2: ISessionFactoryImplementor, IMapping, ISessionFactory, IDisposable, IObjectReference
3 {
4 privado de solo lectura IActualSessionContext currentSessionContext;
5
6 ISession pública GetCurrentSession()
7 {
8 si (this.currentSessionContext == nulo)
9 {
10 lanza una nueva HibernateException (
11 "No hay CurrentSessionContext configurado (establezca la propiedad current_session_context_class)!");
12}
13 devuelve this.currentSessionContext.CurrentSession();
14}
15
16 público ICurrentSessionContext CurrentSessionContext
17 {
18 obtener {return this.currentSessionContext};
19}
20
21 IActualSessionContext privado BuildCurrentSessionContext()
Veintidós {
23 nombre de cadena = PropertiesHelper.GetString("current_session_context_class", this.properties, null);
24 cadenas str2 = nombre;
25 si (cadena2! = nulo)
26 {
27 if (str2 == "llamar") devuelve nuevo CallSessionContext(this);
28 if (str2 == "thread_static") devuelve nuevo ThreadStaticSessionContext(this);
29 if (str2 == "web") devuelve nuevo WebSessionContext(this);
30 if (str2 == "managed_web") devuelve nuevo ManagedWebSessionContext(this);
31}
32 más
33 devuelven nulo;
34 intento
35 {
36 Tipo tipo = ReflectHelper.ClassForName(nombre);
37 retorno (ICurrentSessionContext)Environment.BytecodeProvider.ObjectsFactory
38.CreateInstance(tipo, nuevo objeto[] {este});
39 }
40 capturas (excepción excepcional)
41 {
42 log.Error("No se puede construir el contexto de la sesión actual [" + nombre + "]", excepción);
43 devuelven nulo;
44}
45 }
46 //......
47 }
Cuando se crea una instancia de SessionFactoryImpl, llama al método BuildCurrentSessionContext() (línea 21) para asignar un valor al campo currentSessionContext. El valor específico está determinado por current_session_context_class en el archivo de configuración.
GetCurrentSession() de ISessionFactory llama al método CurrentSession() (línea 6) de ICurrentSessionContext.
El código anterior es bastante simple y todos deben entenderlo.
Hay dos lugares inapropiados en el artículo "Implementación simple de una sesión por solicitud de NHibernate":
1. No todas las solicitudes requieren una sesión para acceder a la base de datos. El código de Global.asax en el artículo realiza WebSessionContext.Bind() al comienzo de todas las solicitudes, lo que desperdiciará una gran cantidad de sesión. Aunque la sesión de NHibernate es liviana, un enfoque más razonable es "realmente necesitar" la vinculación de tiempo.
2. Debido a que el método WebSessionContext.Unbind requiere una instancia de la interfaz ISessionFactory, nos vemos obligados a usar nuestra clase auxiliar (NHibernateSessionFactory o NHibernateHelper) para exponer SessionFactory.
La primera pregunta es más fácil de resolver, así que déjala en la respuesta para comunicarte con todos.
Responderé a la segunda pregunta en el próximo ensayo.
No he aprendido NHibernate durante mucho tiempo y soy un novato. Si hay algún error, ¡corríjame!