NHibernate - mapowanie kolekcji

W tym rozdziale zajmiemy się sposobem reprezentowania kolekcji. Istnieją różne typy kolekcji, z których możemy korzystać w ramach NHibernate, takie jak:

  • Lists
  • Sets
  • Bags

Teraz, z punktu widzenia .NET, mamy do czynienia z listami lub bardzo prostymi strukturami danych, listami, słownikami. NET nie ma wielu różnych typów kolekcji. Dlaczego więc NHibernate potrzebuje wszystkich tych różnych typów? Naprawdę wraca do bazy danych.

Lista

  • Lista to uporządkowany zbiór elementów, które niekoniecznie są unikalne.

  • Możemy to zmapować za pomocą IList <T>.

  • Więc chociaż konwencjonalnie możemy mieć listę adresów, a z punktu widzenia aplikacji wiemy, że elementy są unikalne, nic na liście nie uniemożliwia nam wstawiania zduplikowanych elementów na tej liście.

Zestaw

  • Zestaw to nieuporządkowana kolekcja unikatowych elementów. Jeśli spróbujesz wstawić 2 zduplikowane elementy do zestawu, zgłosi wyjątek.

  • Nie ma w tym nic konkretnego w NHibernate.

  • To po prostu wygodny sposób na implementację zestawu ogólnego. Jeśli korzystasz z platformy .NET 4, możesz użyć nowej wersjiHashSet <T> aby je przedstawić, ale w większości zastosowań NHibernate reprezentujemy to, że jest to ISet.

  • Jest to nieuporządkowane, jeśli wyciągniesz listę adresów z bazy danych lub listy zamówień, nie wiesz, w jakiej kolejności przychodzą, chyba że wprowadzisz określoną klauzulę Order by.

  • Ogólnie rzecz biorąc, dane, które pobierasz z bazy danych, to zbiory.

  • Są to wyjątkowe kolekcje elementów, które są nieuporządkowane.

Torba

  • Inną popularną kolekcją, którą zobaczymy w świecie baz danych, jest torba, która jest jak zestaw, z wyjątkiem tego, że może mieć zduplikowane elementy.

  • W świecie .NET reprezentuje to IList.

Zestawy są prawdopodobnie najpopularniejsze, ale w zależności od zastosowania zobaczysz również listy i torby. Rzućmy okiem na poniższecustomer.hbm.xml plik z ostatniego rozdziału, w którym definiowane są zlecenia 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>

Jak widać, zmapowaliśmy zbiór zamówień jako zestaw. Pamiętaj, że zestaw to nieuporządkowana kolekcja unikatowych elementów.

Teraz, jeśli spojrzysz na klasę Customer, zobaczysz, że właściwość Orders jest zdefiniowana za pomocą ISet, jak pokazano w poniższym programie.

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

Teraz, gdy ta aplikacja zostanie uruchomiona, zobaczysz następujące dane wyjściowe.

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...

Jeśli elementy w kolekcji nie musiałyby być unikalne, gdybyś mógł mieć wiele zamówień z tym samym kluczem podstawowym występującym wiele razy w tej kolekcji, lepiej byłoby to odwzorować jako paczkę, jak pokazano w poniższym programie.

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

Teraz, jeśli uruchomisz tę aplikację, otrzymasz wyjątek, ponieważ jeśli przyjrzymy się klasie klienta, zauważysz, że zamówienia są oznaczone jako ISet w kodzie C #.

Będziemy więc musieli zmienić to na IList, a następnie tutaj musielibyśmy zmienić z HashSet na List w konstruktorze.

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(); 
   } 
}

Po uruchomieniu aplikacji zobaczysz to samo zachowanie. Ale teraz możemy mieć kolejność występującą wiele razy w tej samej kolekcji.

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...