NHibernate 3 (Parte 7) One-To-Many con Inverse

Published on Author lopezLeave a comment

Anterior Post
Siguiente Post

En el anterior ejemplo tenía un problema a resolver: por cada capítulo de un libro nuevo se ejecutaba un INSERT Y un UPDATE, cuando bien podría bastar uno. En este post, uso una manera alternativa de mapear una lista uno-a-varios, usando el atribute inverse. Como ya es usual, el código del ejemplo está en mi AjCodeKata Code Project, en el directorio trunk/NHibernate/BookChapters. Pueden bajarse una versión “congelada a hoy” desde NHibernate3BookChaptersInverse.zip.

Modifiqué la anterior solución, agregando un nuevo proyecto de consola Books.Inverse, copiando el proyecto Books.Console original. Entonces, agregué un nuevo atributo en el mapeo de Book:

<list name="Chapters" cascade="all-delete-orphan" 
  inverse="true">
  <key column="BookId"/>
  <index column="ChapterIndex"/>
  <one-to-many class="Chapter"/>
</list>

El nuevo atributo es inverse=”true”. Con esta pista, NHibernate conoce que el manejo de la lista y sus elementos está bajo el control del programador. ¿Qué implica esto? Ejecuté el nuevo programa de consola: cada capítulo es grabado con un solo INSERT, pero el resultado en la base de datos fue:

No hay BookId, no hay ChapterIndex con valores, son todos null! El problema está en el código original:

cookbook.Chapters.Add(new Chapter() { Title = "Models and Mappings" });
cookbook.Chapters.Add(new Chapter() { Title = "Configuration and Schema" });
cookbook.Chapters.Add(new Chapter() { Title = "Sessions and Transactions" });

Cuando creo un nuevo Chapter, no pongo valores en Book o en su Chapter Index. Esos datos los ponía el NHiberante. Pero ahora con inverse=”true”, esos valores caen bajo mi responsabilidad: NHibernate no interviene. Entonces, para solucionar el problema, cambié la clase Chapter, agregando una nueva propiedad:

// Used in Inverse example
public virtual int ChapterIndex { get; set; }

Y cambié el código a:

cookbook.Chapters.Add(new Chapter() { Title = "Models and Mappings", Book = cookbook, ChapterIndex = 0 });
cookbook.Chapters.Add(new Chapter() { Title = "Configuration and Schema", Book = cookbook, ChapterIndex = 1 });
cookbook.Chapters.Add(new Chapter() { Title = "Sessions and Transactions", Book = cookbook, ChapterIndex = 2 });

Ahora, la salida muestra los insert correctos:

NHibernate: INSERT INTO Books (Title, Author, Id) VALUES (@p0, @p1, @p2);@p0 = 
'NHibernate Cookbook' [Type: String (4000)], @p1 = 'Jason Dentler' 
[Type: String (4000)], @p2 = b643aa0e-1917-4066-96a4-64a09562a58a [Type: Guid (0)]

NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Models and Mappings' [Type: String (4000)], @p1 
 = NULL [Type: String (4000)], @p2 = b643aa0e-1917-4066-96a4-64a09562a58a
 [Type : Guid (0)], @p3 = 0 [Type: Int32 (0)], @p4 = 
 df9114af-7183-4b1b-9826-d12982a898a5 [Type: Guid (0)]
 
NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Configuration and Schema' 
 [Type: String (4000)], @p1 = NULL [Type: String (4000)], @p2 =
 b643aa0e-1917-4066-96a4-64a09562a58a [Type: Guid (0)], @p3 = 1 [Type: Int32 (0)],
 @p4 = 3fc1df36-c7de-4ff8-add2-8f843b627115 [Type: Guid (0)]

NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Sessions and Transactions' 
 [Type: String (4000)], @p1 = NULL [Type: String (4000)], @p2 = 
 b643aa0e-1917-4066-96a4-64a09562a58a  [Type: Guid (0)], @p3 = 2 [Type: Int32 (0)],
 @p4 = 9c8891e4-6419-4469-aa3a-154f2c908985 [Type: Guid (0)]

Los datos grabados están bien:

Todo bien! Noten que no tuve que agregar los capítulos a la sesión de NHibernate: son grabados como parte del libro nuevo, igual que en el anterior ejemplo. Pero con inverse=true, tuve que poner los valores de la relación inversa (de Chapter a Book) y la propiedad de orden que había elegido.

Próximos pasos: explorar borrado y actualización, mapeos más complejos, otras opciones de logging, otras formas de hacer mapeos (como Fluen NHibernate, ConfORM, y el nuevo mapeo por código de NHibernate 3.2).

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Leave a Reply

Your email address will not be published. Required fields are marked *