Posts anteriores: | Empezando con NHibernate Configuración |
Cuando se empieza a trabajar con NH uno de los escollo es el manejo de sesiones; tal vez sea el más grande. La realidad es que hay muy poco que elegir y así muy poco que estudiar.
Los patrones de manejo de sesión son:
- Open session in view (aka session-per-request)
- Request, session y transaction tienen el mismo ciclo de vida
- Session-per-Conversation (aka long-session)
- Permanece abierta por más de un request
- Conversation-per-Business Transaction (CpBT)
- Permanece abierta por el tiempo que dura una transacción de negocio
- Session-per-Call (anti pattern)
- Permanece abierta por el tiempo que dure un query, o un save, o un update…
- Session-per-application
- Imposible usar en una aplicación real
- Más que un pattern es una “Time bomb”
Sobre los último dos no vale la pena gastar ni una línea.
Con Session-per-Conversation (eschema disponible aquí) hay que tener cuidado porque no siempre funciona como uno se espera (léase abrir dos tabs en lugar que dos instancias de browser). Hay frameworks que facilitan el uso de session-per-request en mix con session-per-conversation y limitan la cantidad de conversations iniciadas a una. A mi gusto quedan sesión-per-request y conversation-per-business transaction (eschema disponible aquí).
Si pueden organizar la aplicación para usar session-per-request siempre, sería una buena solución. Si notan que los use-case, que necesitan una trasaction de negocio que involucra más de un request, son muchos, vayan pensando que session-per-request, en algún momento, le puede quedar corto. Si la aplicación es WinForm o WPF olvídense de session-per-request por el simple motivo que en esos ambientes no existe nada parecido a un request (ni siquiera el Call-context lo es).
Las recomendaciones
- Recuerden que la session implementa UnitOfWork; la implementación del pattern UnitOfWork es la session de NHibernate.
- Traten de mantener en la session lo que realmente se necesita que esté en la UnitOfWork; el Flush podría ser muy laaargo.
- “Abracen” todas acciones de persistencia con una transaction, no importa que sean de lectura o escrictura.
- Haganse la idea que la ISession no es la IDbConnection.
- Haganse la idea que la ITransaction no es la IDbTransaction.
- No encierren la ISession en una clase con Save, Update, FindBy etc., es completamente innecesario; en el DAO/Repository usen la ISession.
- Si algo "no funciona" ante de pensar que sea un bug de NHibernate intenten escribir un test que reproduzca el error afuera de su aplicación (NH es muy usado, en el mundo, en varios entornos y en aplicaciones comerciales).
- Antes de escribir su session-handler averigüen quien ya lo hizo; no intenten inventar, ya somos muchos los que han golpeado la cabeza, ustedes, en lo posible, evítenlo.
- Asegúrense que su capa de acceso a datos (DAO o Repository) permita cambiar la estrategia de gestión de sesiones de persistencia; por ejemplo inyectando ISessionFactory a su DAO y usando GetCurrentSession(tambien se puede inyectar la ISession pero, en ese caso, asegúrense de conocer lo que pierden).
- Eviten que sus DAO/Repository tengan referencia a un session-handler especifico (aunque suene similar no es lo mismo del punto anterior); en lo posible mantengan la implementación de DAO/Repository pegada solo y exclusivamente a NH.
- Recuerden que el manejo de sesiones de persistencia es algo más cercano al manejo de cuestiones de infraestructura.
- Al primer problema relacionado con lazy-loading asegúrense usar una estrategia de manejo de sesiones adecuada al caso de uso.
- Si piensan necesitar un ISession.Evict preocúpense; es posible que el manejo de sesiones no sea el adecuado. Ni hablar si ven una aplicación con Evict por todos lados. El Evict es útil solo en algunos casos especiales.
- Sepan que ISession no es solo Get, SaveOrUpdate, CreateQuery y CreateCriteria.
- Investiguen porque parece que NH tiene dos métodos para hacer lo mismo; Get y Load no son lo mismo.
- Aprendan a trabajar con entidades desconectadas (ISession.Lock, ISession.Merge)
- Averigüen de qué se trata con IStatelessSession.
Donde encontrar session handlers
La primer fuente es NHibernate mismo. El name space NHibernate.Context contiene la clase WebSessionContext para manejo de sessiones en WEB y ThreadStaticSessionContext para manejo de sesiones en tests. Usando WebSessionContext no necesitan nada mas (a parte una implementación de IHttpModule) para manejar session-per-request y/o session-per-conversation en entorno WEB. Notar que las implementaciones disponibles en NHibernate se basan en el uso de GetCurrentSession y son descripats en NHibernate in Action.
Castle y Spring.NET ofrecen “semplificadores” de manejo de sessiones en WEB, WinForm y tests.
RhinoTools ofrece una implementación para WEB (session-per-request y/o session-per-conversation).
NHibernate.Burrow provee varias formas de manejo de sesiones orientado a WEB. Burrow tambien implementa algo muy similar a CpBT o mejor dicho implementa session-per-conversation sin limitaciones a una sola convesación por HttpSession.
uNhAddIns implementa todos los patterns. Como la implementación en NHibernate-Core tambien las implementaciones en uNhAddIns se basan en el uso de GetCurrentSession. Las implementaciones son disponibles en el namespace uNhAddIns.SessionEasier y uNhAddIns.Web.SessionEasier. La implementaciones de session-per-request y session-per-conversation ofrecen un uso “semplificado” respecto a las implementaciones en el core de NH ya que el Bind/Unbind es automatico (el Unbind automatico se activa solo si aceptan usar algún DynamicProxy, por ejemplo el mismo que usan en NH). Para lo que concierne la implementación de CpBT los invito a leer varios posts. Como ultima nota, sobre uNhAddIns, les aclaro que uNhAddIns no trae dependencias a algo mas que no sea NHibernate, todas las implementaciones de session-handlers pueden ser usadas a solas o con el IoC/AOP que prefieran.