Try fast search NHibernate

01 May 2009

Empezando con NH: mappings

Posts anteriores: Empezando con NHibernate
Configuración
Session

El mapping es el “leguaje de programación” de NHibernate. Cada línea de mapping se compila en el momento de construir el session-factory (configuration.BuildSessionFactory).

Hasta antes que saliera NH1.2.0 la regla que divulgaba, para el mapping, era “decile a NH lo que ya sabes; no lo hagas trabajar demás”. Esta regla funcionaba muy bien en tanto uno supiera que es lo que le está diciendo a NH. Mientras trabajábamos en NH2.0.0 me di cuenta que el copy&paste es una actividad muy usada, escribiendo mappings, y el resultado, en muchos casos, era un desastre (especialmente si no se miran las SQLs generadas). Estaba claro que había que trabajar para cambiar la regla.

La regla maestra para escribir mappings (a parte de conocer bien las técnicas de ORM) es:

“No aclares que oscurece”

Este es un mapping que uso en mis cursos:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Starting.NH"
namespace="Starting.NH.OptimisticLock.Revision">

<
class name="Task">
<
id type="int">
<
generator class="hilo"/>
</
id>
<
version name="Version"/>
<
property name="Description"/>
</
class>

</
hibernate-mapping>

Notar que el “type” del POID está allí solo porque la implementación de la entity no tiene una propiedad para el ID.

Cuando uno empieza con NHibernate lo primero que busca es “algo” que escriba los mappings; me pasó también a mi (recuerdo haberle dedicado un par de horas, pero todo empezaba por las tablas). Como le he contado en un post anterior trabajar con NH y no conocer ORM no es una opción y lo peor que pueden hacer es generar los mappings usando como origen las tablas. Si buscan generadores de mappings busquen algo que trabaje con un DSL que describa su entorno de negocio.

Ahora viene lo difícil… El mapping de NH es muy flexible y la cantidad de combinaciones posibles es muy, pero muy, grande; intentaré definir una serie de recomendaciones más bien genérica.

Las recomendaciones

  • Estudien las técnicas de ORM; los mappings son ORM aplicado. No todo es <subclass> así como tampoco todo es <joined-subclass>.

  • No aclaren que oscurece; escriban lo menos posible. Con que la sintaxis sea correcta, por lo general, alcanza.

  • Copien el file nhibernate-mapping.xsd en las “external lib” del proyecto y no en las carpetas de VisualStudio.

  • Mientras escriban el mapping usen siempre el schema; el intellisense es una masa y hay que aprovecharlo.

  • Trabajen por diferencia; si saben que un valor es el default no lo escriban (por ejemplo el default para el nombre de la columna es el nombre de la propiedad).

  • No usen unsaved-value si van a escribir el default del type del Id o de la versión y, en lo posible, no inventen cosas raras solo para escribir un unsaved-value (si un id jamás puede ser cero ¿que razones hay de usar otro valor? )

  • Definan assembly y namespace en el header del mapping (ver ejemplo arriba).

  • Si abren un mapping y le cuesta leerlo (le duelen los ojos) es porque no cumplieron con la regla maestra.

  • No usen default-cascade=”save-update”; el cascade hay que declararlo bien y donde corresponde.

  • Si van usar implementaciones de IUserType, IUserCollectionType o IUserVersionType usen el tag <typedef>.

  • Escriban todos queries estáticos en el mapping y no en el código; los queries en el mapping sobre todo son compilado, son intercambiables entre HQL y SQL, las características de comportamiento se definen en el mapping (por ejemplo por lo que concierne la cache).

  • Recuerden que el cascade no es un solo valor (es comma-separated-values) y no es todo all-delete-orphan.

  • Usen default_schema, default_catalog de la configuración del session-factory y los attributes schema, catalog, del header del mapping solo si trabajan multi-rdbms.

  • Usen los tags DDL oriented (como length, precision, scale, not-null etc.) cuando corresponde. Escribir “string(100)” o “Double(18,5)” tambien es bueno.

  • No usen el nodo <column> si no es necesario; casi siempre los attributes del nodo <property> alcanzan.

  • Para las collections no existe solo <bag>; estudien los otros tipos de collections.

  • No le tengan miedo al <set>; cuando Microsoft nos escuche y ponga una interface parecida a ISet usaremos la del framework. Notar que usar Iesi.Collections no significa poner una dependencia a NH en sus entidades, para nada, a parte que en la entity pueden usar ICollection<T> mapeado a un <set>.

  • Si piensan necesitar los tags where, order-by, formula asegúrense de no estar delegando cuestiones de negocio a NHibernate y tengan en mente que de servidor de DB hay uno, y es caro, y de servidores de aplicación hay varios y son más barato.

Fluent-NHibernate

Fluent-NH es una opción para escribir mappings pero todas las recomendaciones anteriores siguen valiendo. Tengan presente que Fluent-NH genera XML y que el XML generado hace doler los ojos. Por otro lado Fluent-NH no suporta todas las features que suporta el mapping XML así como el mapping XML no suporta todas la features que se pueden implementar usando C#.

No soy adivino y no sé qué pasará cuando empezaremos NH3.0.0. Lo que si se, es que NH tendrá su mapping basado en fluent interface (Loquacious como lo llamamos en NHV) y que no generará XML (creará directamente los meta-data).

3 comments:

  1. buenisimo, gracias a este thread y a otro tuyo, termine de comprender, un poco mas como trabaja nhibernate, uow y porque elegir hilo como id generator
    muy bueno

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete