NHibernate - Mapeo de colecciones

En este capítulo, cubriremos cómo representar colecciones. Hay diferentes tipos de colecciones que podemos usar dentro de NHibernate como:

  • Lists
  • Sets
  • Bags

Ahora, desde la perspectiva de .NET, generalmente tratamos con listas o como estructuras de datos muy simples, listas, diccionarios. .NET no tiene una amplia variedad de tipos de colecciones diferentes. Entonces, ¿por qué NHibernate necesita todos estos tipos diferentes? Realmente vuelve a la base de datos.

Lista

  • Una lista es una colección ordenada de elementos que no son necesariamente únicos.

  • Podemos mapear esto usando el IList <T>.

  • Entonces, aunque convencionalmente podríamos tener una lista de direcciones, y desde el punto de vista de la aplicación sabemos que los elementos son únicos, nada en la lista nos impide insertar elementos duplicados en esa lista.

Conjunto

  • Un conjunto es una colección desordenada de elementos únicos. Si intenta insertar 2 elementos duplicados en un conjunto, generará una excepción.

  • No hay nada específico en NHibernate al respecto.

  • Es solo una forma conveniente de tener una implementación de conjunto genérico. Si está en .NET 4, puede usar el nuevoHashSet <T> para representarlos, pero en la mayoría de las aplicaciones de NHibernate, representamos que se trata de un ISet.

  • No está ordenado, si extrae una lista de direcciones de una base de datos o una lista de pedidos, no sabe en qué orden vienen a menos que ingrese una cláusula específica de Orden por.

  • Entonces, en general, los datos que extrae de una base de datos son conjuntos.

  • Son colecciones únicas de elementos que no están ordenados.

Bolso

  • Otra colección común que veremos en el mundo de las bases de datos es una bolsa, que es como un conjunto, excepto que puede tener elementos duplicados.

  • En el mundo .NET, representamos esto mediante un IList.

Los conjuntos son probablemente los más comunes, pero también verá listas y bolsas según su aplicación. Echemos un vistazo a abajocustomer.hbm.xml Archivo del último capítulo en el que se definen las órdenes de Set.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo" 
   namespace = "NHibernateDemo"> 
	
   <class name = "Customer"> 
      
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Como puede ver, hemos mapeado la colección de pedidos como un conjunto. Recuerde que un conjunto es una colección desordenada de elementos únicos.

Ahora, si observa la clase Cliente, verá que la propiedad Pedidos está definida con un ISet como se muestra en el siguiente programa.

public virtual ISet<Order> Orders { get; set; }

Ahora, cuando se ejecute esta aplicación, verá el siguiente resultado.

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7

The orders were ordered by:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7

John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
		
Press <ENTER> to exit...

Si los elementos de la colección no necesitaban ser únicos, si pudiera tener varios pedidos con la misma clave principal que se produzcan varias veces en esta colección, entonces sería mejor mapearlo como una bolsa como se muestra en el siguiente programa.

<bag name = "Orders" table = "`Order`"> 
   <key column = "CustomerId"/> 
   <one-to-many class = "Order"/> 
</bag>

Ahora, si ejecuta esta aplicación obtendrá una excepción porque si echamos un vistazo a la clase de cliente, notará que los pedidos están marcados como ISet en el código C #.

Así que también tendremos que cambiar esto a un IList y luego aquí, necesitaríamos cambiar de HashSet a List en el constructor.

public class Customer { 

   public Customer() { 
      MemberSince = DateTime.UtcNow; 
      Orders = new List<Order>(); 
   } 
	
   public virtual Guid Id { get; set; } 
   public virtual string FirstName { get; set; } 
   public virtual string LastName { get; set; } 
   public virtual double AverageRating { get; set; } 
   public virtual int Points { get; set; } 
	
   public virtual bool HasGoldStatus { get; set; } 
   public virtual DateTime MemberSince { get; set; } 
   public virtual CustomerCreditRating CreditRating { get; set; } 
   public virtual Location Address { get; set; }
   public virtual IList<Order> Orders { get; set; }
   public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
   
   public override string ToString() { 
      var result = new StringBuilder(); 
		
      result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
         {4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
         {8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
         CreditRating, MemberSince.Kind, AverageRating); result.AppendLine("\tOrders:"); 
      
      foreach(var order in Orders) { 
         result.AppendLine("\t\t" + order); 
      } 
		
      return result.ToString(); 
   } 
}

Cuando ejecute la aplicación, verá el mismo comportamiento. Pero ahora podemos tener un orden que ocurre varias veces en la misma colección.

John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287

The orders were ordered by:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287

John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
		
Press <ENTER> to exit...