Try fast search NHibernate

29 April 2009

Empezando con NH: configuración

Posts anteriores: Empezando con NHibernate

De aquí en más, cuando haga referencia a NHibernate (NH), usaré NH2.1.0.

NH es un framework muy flexible y por ese motivo la configuración de la session-factory es bastante extensa; sin embargo nadie nos obliga a usar o definir un valor para todas las features suportadas por NH. Acá les muestro la configuración que uso para mis cursos de introducción a NHibernate:

<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
<
session-factory name="StartingNH">
<
property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>

<
property name="connection.connection_string_name">StartingNH</property>
<
property name="connection.isolation">ReadCommitted</property>

<
property name='proxyfactory.factory_class'>
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
</property>

<
property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>

<
property name="adonet.batch_size">50</property>

<
property name="command_timeout">10</property>

<
property name="format_sql">true</property>

</
session-factory>
</
hibernate-configuration>

Esta configuración puede ser usada tranquilamente en producción. Para su entorno de desarrollo, tal vez, sea mejor usar la propiedad connection.connection_string en lugar que user connection.connection_string_name.

En realidad una configuración perfectamente valida es:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >

<
session-factory>
<
property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<
property name="connection.connection_string">
Data Source=localhost\SQLEXPRESS;Initial Catalog=BlogSpot;Integrated Security=True
</property>

<
property name='proxyfactory.factory_class'>
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
</property>
</
session-factory>
</
hibernate-configuration>

Como verán son tres las cosas que NH necesita para poder funcionar:

  1. El Dialect del RDBMS que vamos a usar (y hasta eso es opciónal pero bueno…)
  2. La connection string
  3. El sistema de DynamicProxy que usará para trabajar en forma transparente con lazy-loading.

No me digan que esa es una configuración compleja.

Hay otra parte de la configuración que, no es de NH pero, es importante en fase de desarrollo/tests: la configuración de log4net.

Acá va una muestra:

<log4net debug="false">
<
appender name="console" type="log4net.Appender.ConsoleAppender, log4net">
<
layout type="log4net.Layout.PatternLayout,log4net">
<
param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" />
</
layout>
</
appender>

<
appender name="CleanConsole" type="log4net.Appender.ConsoleAppender, log4net">
<
layout type="log4net.Layout.PatternLayout,log4net">
<
param name="ConversionPattern" value="%m%n" />
</
layout>
</
appender>

<
appender name="RollingFile" type="log4net.Appender.RollingFileAppender,log4net" >
<
param name="File" value="NHibernateLog.txt" />
<
param name="AppendToFile" value="false" />
<
param name="RollingStyle" value="Date" />
<
param name="DatePattern" value="yyyy.MM.dd" />
<
param name="StaticLogFileName" value="true" />

<
layout type="log4net.Layout.PatternLayout,log4net">
<
param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</
layout>
</
appender>

<
root>
<
priority value="WARN" />
<
appender-ref ref="RollingFile" />
</
root>

<
logger name="NHibernate.SQL">
<
level value="OFF" />
</
logger>

<
logger name="NHibernate.Tool.hbm2ddl.SchemaExport">
<
level value="ERROR" />
</
logger>
</
log4net>

Para quien no conoce log4Net aclaro que lo que está siempre activo son dos niveles de log: el WARN (warning) y el ERROR para el SchemaExport que es para quien usamos NH tambien para generar el DB schema en fase de tests.

Las recomandaciones para NH

  • Eviten usar frameworks que "ocultan" la configuración de NH; enrollar un XML con otro XML no tiene sentido (hasta que alguien demuestre lo contrario).

  • Si quieren usar algún framework que permita la configuración por codigo asegurense que lo haga heredando de NHibernate.Cfg.Configuration y/o usando una implementación de IHibernateConfiguration y no generando otro XML.

  • Nombren la/las session-factory especialmente si trabajan en multi-rdbms. El nombre de la session-factory puede ser la key para encontrar la session-factory asociada a un determinado DAO/Repository.

  • Definan siempre el isolation level aunque cada Drive tenga ya su default; los valores admitidos son definidos en System.Data.IsolationLevel.

  • Usen el tag <mapping> para agregar sus mappings a una configuración.

  • No olviden definir query.substitutions; evitarán sorpresas cuando ejecuten HQLs en donde especifiquen valores de clases (true,false) y no valore de DB (1 o 0).

  • Si saben que su drive suporta la ejecución de queries en batch (más de un queries en un solo round-trip) definan adonet.batch_size; si no lo definen el batcher no se activa y la diferencia en performance puede ser notable.

  • Definan el command_timeout (en segundos) a un valor congruo para su aplicación; en mi forma de endender si un comando SQL lleva mas de 10 segundos algo anda mal.

  • Controlar alguna SQL generada por NH puede ser un desafió no de poco (especialmente cuando le toman la mano al ORM). Configurar format_sql a true le permitirá ver las SQL en un formato mas human-readable (NO todo en una sola linea).

  • En desarrollo usen el file hibernate.cfg.xml y una base de datos local y no usen el App.config y base de datos común para los tests; cada desarrollador tiene el derecho de tener la base en local con su connection-string y hacer debug sin preocuparse de bloquear a los otros desarrolladores. El file hibernate.cfg.xml tendrá que ser excluido del repository de fuentes (svn:ignore) mientras que se puede incluir un file hibernate.cfg.template para que cada desarrollador tenga un ejemplo.

  • No activen la cache (aka second level cache) hasta que la applicación no tenga por lo menos una versión en producción. La cache no es la panacea de las performance; una applicación debe funcionar bien sin cache… luego le pondrán el “turbo” si y donde lo necesita.

Las recomandaciones para el logging

  • No olviden configurar el logging de NHibernate.

  • Ya que lo tendrán activo no olviden leerlo; en NH nos costó bastante definir algunos niveles de log y si se loguea un WARNING, en casi todos los casos, es porque hay que prestar attención a algo que está pasando. Ni hablar si el log es un ERROR.

  • Cuando escriban behavior-tests, con o sin WatIn, activen el log “NHibernate.SQL” a DEBUG y miren las SQL que NH está generando. Este proceso es indispensable en fase de optimización de la applicación.

  • Por lo mismos motivos del file de configuración de NH usen un file tambien para la configuración de log4net (no usen el App.config) y escluyan ese file del repository de fuentes; cada desarrollador tiene el derecho de activar los logs que necesite.

No comments:

Post a Comment