Posteado por: Victor Mingueza | 2010/04/24

Illegal Two Sessions con Castle en NHibernate

Voy a intentar de explicar esta excepción con NHibernate, para que veamos como podemos llegar a reproducirla y que debemos hacer para poder evitarla y en el caso de no poder modificar mucho la arquitectura de la aplicación como podemos solucionar este problema haciendo uso de la implementación de los proxy con Castle.

Illegal attempt to associate a collection with two open sessions

Esta excepción sucede normalmente en aplicaciones de escritorio ya que las aplicaciones web se suele hacer uso del patrón OpenSessionInview, que simplifica mucho el manejo de las sesiones con NHibernate. Como explique anteriormente.

En el caso de aplicaciones de escritorio que la duración de una sesión viene determinada por la arquitectura que tengamos empleada y no por cada petición puede saltar la siguiente excepción al intentar guardar o eliminar un objeto de la bb.dd.

NHibernate.HibernateException: Illegal attempt to associate a collection with two open sessions.

Arquitectura recomendada

Voy a poner un ejemplo de arquitectura que nos solventaría estos problemas y recomiendo para el uso de aplicaciones de escritorio donde el  manejo de sesiones sea un poco mas peliagudo.

image Esta seria la organización de mis capas en un proyecto y ahora explicare porque lo he organizado así y la dependencia de cada una de ellas.

Primero todas las capas dependen del Dominio especifico de la aplicación (Entidades y ficheros HBM), algunos puristas dirán que no es conveniente usar objetos del dominio en la capa de presentación. Pero a veces no es necesario crear entidades intermedias las cuales complican y alargan el desarrollo.

Me gusta tener la capa de dominio aislada porque esto me permite que mi capa de datos sea totalmente abstracta haciendo uso de Generics y ajena al negocio con lo cual la puede tener como una librería independiente que asocio a mi aplicación cuando quiero hacer uso de ella.

Mi capa de Negocio es la cual contiene toda la lógica característica del desarrollo. y en la cual definiré mis unidades básicas de trabajo o “Servicios”. Cada uno de estos servicios serán los encargados de hacer uso de la capa de datos y del dominio y pasar las validaciones devolver consultas especificas… Puede ser que un servicio tenga muchos métodos y se vuelva algo inmanejable pero para ello hago uso de las clases parciales dividiéndola en varios archivos, uno para consultas,  otro validaciones…Esto cada uno como quiera.

Bien lo mas importante de estos servicios es saber acotarlos bien ya que estos serán nuestras Unit Of Work. Cada uno de ellos manejara una sesión y para guardar datos haciendo uso de varios servicios estos tendrán llamadas entre si.

public Entity1 Save(Entity1 entity)
{
     ServiceFactory.OtherService.DoSomething(entity.Collection);
     return GenericDao.SaveOrUpdate<Entity1>(entity);
}

Como habéis podido ver esto nos permite ver claramente las transacciones como en el caso que ambas sentencias. Las cuales se harían dentro de una misma transacción.

Ademas como habéis podido ver el acceso a los servicios lo hago a través de una factoría que se encarga de que cada servicio sea instanciado una sola vez mejorando el uso de caches.

Por ultimo la capa de presentación se encargaría de hacer llamadas a nuestros servicios y mostrar los datos. Lo cual nos facilitaría el cambio de una presentación a otra ya sea web, wpf, windows forms. Ya que toda la lógica estaría bien aislada.

Saliendo del paso con Castle

Si estamos en un avanzado estado del proyecto, no podremos tocar mucho la arquitectura del mismo, pero si podemos evitar esta excepción, haciendo uso del ByteCodeProvider de Castle.

Para ello en la configuración hay que indicarle a NHibernate que los proxy los manejara Castle indicando en su variable:

Proxyfactory.Factory_Class, que haga uso de NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle

También será necesario hacer referencia a las siguientes DLLs en el proyecto

  • Castle.Core
  • Castle.DinamicProxy2
  • NHibernate.ByteCode.Castle

Por último en nuestra capa de datos obtendremos el proxy de nuestra entidad a persistir y si tiene una sesión activa haremos un Evict de esta para asociarla a la nueva sesión y evitar el error de la siguiente forma:

<Transaction(TransactionPropagation.Required, IsolationLevel.RepeatableRead)> _
Public Overloads Sub Delete(Of T)(ByVal entity As T) Implements IGenericDao.Delete
  Try
  'En el caso de que haya sido leído con otra sesión esta queda asociada al objeto
  'por eso debemos hacer un detach de esta y ya podemos eliminar normalmente-
  If entity.GetType().GetProperty("HibernateLazyInitializer") IsNot Nothing Then
   Dim proxy As NHibernate.Bytecode.Castle.LazyInitializer =
       entity.GetType().GetProperty("HibernateLazyInitializer").GetValue(entity, Nothing)
   proxy.Session.CloseSessionFromDistributedTransaction()
  End If
  HibernateTemplate.Delete(entity)
  Catch ex As Exception
   Throw ex
  End Try
End Sub
 

Buenos y esto es todo, con esto podremos salir del paso en el caso que nos de la molesta excepción :

Illegal attempt to associate a collection with two open sessions

PD: Los gráficos los he hecho haciendo uso de Gliffy, una gran pagina que me recomendó un amigo. Ya que con el VS2010 aun no me atrevo 🙂

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

[tweetmeme source=”mingue” only_single=false]
Posteado por: Victor Mingueza | 2010/03/25

Habilitar cache de segundo nivel en NHibernate

NHibernate nos permite optimizar la carga de base de datos habilitando varias caches, la primera de ellas esta habilitada por defecto y es una cache para el ámbito de la sesión.

Por cada sesión que abrimos con la base de datos NHibernate nos crea una cache que permite que si en la misma sesión vamos a cargar el mismo objeto o alguno objeto que haya sido carga a través de una colección de este, nos evite ir a base de datos para volver a cargarlo.

image

La segunda no viene habilitada por defecto, hay que hacerlo manualmente y hay que tener en cuenta una serie de condiciones antes de habilitarla, ya que supone una gran eficiencia, pero puede llevar algunos riesgos.

image

Por ejemplo, en el caso de ser una aplicación de Windows forms, cada usuario podría tener una cache independientes (si la capa de datos esta distribuida en cada cliente) con lo que las modificaciones que realice un usuario, el otro usuario no las vería hasta que no destruya el session factory, que normalmente suele durar hasta que se cierre la aplicación.

Una forma de solucionar esto seria hacer uso de caches distribuidas, pero para ello nuestros objetos de NHibernate deberían de ser serializables y esto con la carga perezosa puede llevar algunos problemas. Ya intentare explicar esto un poco mejor en otro post ya que el tema es peliagudo.

Esto mismo se aplicaría a aplicaciones orientadas a servicios, en el caso de querer enviar nuestras entidades de NHibernate, habría que serializarlas y estaríamos en el mismo punto. En este caso seria mejor hacer uso de DTOs (Data Transfer Objects).

Pero en cambio para el caso de aplicaciones web. Al ejecutarse todo el código en la misma maquina, podemos hacer uso de esta cache sin que ello conlleve muchas complicaciones.

Para realizarlo hay que modificar las siguiente propiedades en la configuración del session factory.

<entry key="cache.use_second_level_cache"  value="true"/>
<entry key="cache.use_query_cache" value="true"/>
<entry key="cache.provider_class" 
     value="NHibernate.Caches.SysCache.SysCacheProvider,
              NHibernate.Caches.SysCache"/>

Yo lo tengo así configurado porque hago uso de Spring.Net, pero las propiedades a modificar son las mismas en una configuración sin Spring. Se pueden hacer uso de distintas caches pero para ASP.Net y una aplicación sencilla es mejor usar la cache integrada “SysCache”. En el post que indico al final podéis ver los distintos tipos de caches que existen y las distintas implementaciones que podemos usar las entrareis aquí: NHibernate Contrib

Hibernating Rhinos post

Un saludo

Posteado por: Victor Mingueza | 2010/03/06

OpenSessionInView en IIS7

Al cambiar un proyecto de ASP.Net a IIS7, si estamos haciendo uso del patrón OpenSessionInView con Spring.Net y NHibernate, recibimos la excepción de LazyInitializationException al intentar cargar una clave ajena o una colección.

  Existe la posibilidad de usar este patrón, que permite hacer uso de la carga perezosa mientras dure la petición al servidor y se termina de renderizar la página.

OpenSessionInView

El problema de esto es que a partir de IIS7, el integrated pipeline pinta poco por lo que hay que mover la declaración de los módulos de Spring desde System.Web.httpModules a System.webserver.Modules, para poder hacer uso de la carga perezosa en la sesión.

<system.web>
 <httpModules>
  <add name="SpringModule" 
           type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
  <add name="OpenSessionInView" 
       type="Spring.Data.NHibernate.Support.OpenSessionInViewModule,
       Spring.Data.NHibernate21"/>
  </httpModules>
</system.web>
 
 

<system.webServer>
 <modules>
  <add name="SpringModule" 
           type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
  <add name="OpenSessionInView" 
       type="Spring.Data.NHibernate.Support.OpenSessionInViewModule,
       Spring.Data.NHibernate21"/>
  </modules>
</system.webServer>
 
Si dejamos la declaración en ambas partes no será necesario cambiar
el archivo de configuración para que funcione en uno o otro servidor.
 
Un saludo
Posteado por: Victor Mingueza | 2010/02/19

NHibernate vs Entity Framework 4.0

 

image    
 

VS

image

 

Leyendo sobre el tema me encontré con este post NHibernate vs Entity Framework, de Ayende Rahein y tomo muy en serio su palabra ya que es gran conocedor de la arquitectura y del funcionamiento de ambas aplicaciones, ya que es un miembro del equipo de desarrollo de NHibernate y creador de NHibernae Profiler y ahora también de Entity Framework Profiler, herramientas muy recomendadas para encontrar los cuellos de botella de las aplicaciones y mejorar el rendimiento de estas.

Como principales cosas a destacar:

NHibernate posee Write Batching, que permite guardar un bloque de entidades en un solo viaje a la base de datos en lugar de realizar el guardado uno a uno. Esto es algo que acabo de implementar en una aplicación y expondré como utilizarlo junto con Spring.

NHibernate además destaca también por tener Read Batching, que básicamente es lo que podéis imaginar, ejecución de varias consultas en un mismo viaje a la base de datos.

Colección with lazy=”extra”, una utilidad muy interesante que da mas inteligencia y te permite hilar mas fino jugando con la carga perezosa y las colecciones, ya que permite hacer count de las colecciones sin necesidad de cargar todas las entidades de bb.dd. y item.Colección.Contains() en lugar de cargar la Colección realizara una simple query a bb.dd. para ver si contiene ese elemento sin necesidad de cargar lo demás.

Colección Filters & Paged Collections, que nos permite definir filtros a nivel de colección o paginación de las mismas a nivel de mapeo de nuestras entidades.

2nd level cache, la cache compartida entre todas nuestras sesiones de un mismo Session Factory, lo que agiliza muchísimo la base de datos y que en web es muy sencillo de implementar sin correr demasiados riesgos de concurrencia. Aquí tenéis un ejemplo de uso

Tweaking, y es que NHibernate te permite hilar mucho mas fino que Entity Framework que además es un producto cerrado que no permite ampliar su funcionalidad por lo que no pueden existir frameworks que añadan funcionalidad a este como puede ser el caso de NHibernate Search, NHibernate Validator, NHibernate Shards… Integration & Extensibility

Por otra parte, destaca que Entity Framework tiene de momento una mejor integración con Linq (faltaría menos jeje) y que es de Microsoft, aunque esta realmente no se si es una ventaja al ser un producto cerrado que no permite su extensibilidad ni modificar algunos de los comportamientos que ofrece

Además, yo destacaría que Entity Framework tiene la gran ventaja de que el programador no tenga que empaparse de como funciona internamente ya que tiene herramientas graficas que realizan todo por ti aunque esto es un arma de doble filo ya que de esta forma no llegas comprender su funcionamiento interno. Aunque existen herramientas para NHibernate como NConstruct Lite, que nos permiten ahorrarnos la gran mayoría de mapeos y generación de clases (Conocéis vosotros alguna mejor)

Un saludo, espero ir posteando algunas cosas que tengo guardadas para mejorar nuestras aplicaciones con NHibernate y Spring.Net

Posteado por: Victor Mingueza | 2010/02/16

MeeGo la revolución de los Netbooks, móviles…

En el Mobile World Congress que se está celebrando en Barcelona, Nokia e Intel acaban de presentar el proyecto MeeGo. Se trata de la fusión de Maemo (Nokia) y Moblin (Intel). Según se autodefinen, MeeGo será un sistema pensado para ‘netbooks’, escritorios a nivel básico, dispositivos portátiles, televisiones conectadas y teléfonos multimedia. A nivel de sistema operativo, será una distribución Linux con soporte de ARM e Intel/Atom, y a nivel de interfaz usarán principalmente Qt, aunque también tendrán soporte de GTK y Clutter. La organización del proyecto corre a cargo de la Linux Foundation. Se espera que la versión 1 se publique en el segundo trimestre de 2010.

Via http://barrapunto.com/

image 

El proyecto a mi parecer ya ha empezado a perder en lo que a presentación se refiere y es que no nos engañemos lo que le dio la gran fama a Moblin, para que todas las distribuciones lo quisieran era su aspecto y de momento la web esta perdiendo bastante era mucho mejor la de moblin y mas sencilla que la actual. Esperemos que esos videos que se encargaban de realizar para las presentaciones muy al estilo Mac pero animados no se pierdan ya que creo que era el gran empuje de esta distribución; La sencillez y el diseño de su interfaz

« Newer Posts - Older Posts »

Categorías