NHibernate - Mappatura della raccolta
In questo capitolo vedremo come rappresentare le collezioni. Esistono diversi tipi di raccolte che possiamo utilizzare all'interno di NHibernate come:
- Lists
- Sets
- Bags
Ora, dal punto di vista .NET, generalmente ci occupiamo di elenchi o come strutture dati molto semplici, elenchi, dizionari. .NET non dispone di un'ampia varietà di diversi tipi di raccolta. Allora perché NHibernate ha bisogno di tutti questi diversi tipi? Torna davvero al database.
Elenco
Un elenco è una raccolta ordinata di elementi che non sono necessariamente univoci.
Possiamo mapparlo usando il IList <T>.
Quindi, anche se convenzionalmente potremmo avere un elenco di indirizzi e dal punto di vista dell'applicazione sappiamo che gli elementi sono unici, nulla nell'elenco ci impedisce di inserire elementi duplicati in quell'elenco.
Impostato
Un set è una raccolta non ordinata di elementi unici. Se provi a inserire 2 elementi duplicati in un set, verrà generata un'eccezione.
Non c'è niente di specifico in NHibernate al riguardo.
È solo un modo conveniente per avere un'implementazione del set generico. Se sei su .NET 4, puoi usare il nuovoHashSet <T> per rappresentarli, ma nella maggior parte delle applicazioni NHibernate, rappresentiamo che questo è un ISet.
È un ordine non ordinato, se estrai un elenco di indirizzi da un database o un elenco di ordini, non sai in quale ordine stanno arrivando a meno che tu non inserisca una specifica clausola Order by.
Quindi, in generale, i dati che stai ritirando da un database sono set.
Sono raccolte uniche di elementi non ordinati.
Borsa
Un'altra collezione comune che vedremo nel mondo del database è una borsa, che è proprio come un set tranne che può avere elementi duplicati.
Nel mondo .NET, lo rappresentiamo da un IList.
I set sono probabilmente i più comuni, ma vedrai anche elenchi e borse a seconda dell'applicazione. Diamo uno sguardo a un sottocustomer.hbm.xml file dell'ultimo capitolo in cui sono definiti gli ordini di 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>
Come puoi vedere, abbiamo mappato la raccolta degli ordini come un set. Ricorda che un set è una raccolta non ordinata di elementi unici.
Ora, se guardi la classe Customer, vedrai che la proprietà Orders è definita con un ISet come mostrato nel programma seguente.
public virtual ISet<Order> Orders { get; set; }
Ora quando questa applicazione viene eseguita, vedrai il seguente output.
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...
Se gli articoli nella raccolta non dovevano essere univoci, se potessi avere più ordini con la stessa chiave primaria che si verificano più volte in questa raccolta, allora questo sarebbe meglio mappato come borsa come mostrato nel programma seguente.
<bag name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</bag>
Ora, se esegui questa applicazione otterrai un'eccezione perché se diamo un'occhiata alla classe del cliente, noterai che gli ordini sono contrassegnati come ISet nel codice C #.
Quindi dovremo anche cambiarlo in IList e quindi qui, dovremmo cambiare da HashSet a List nel costruttore.
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();
}
}
Quando esegui l'applicazione, vedrai lo stesso comportamento. Ma ora possiamo avere un ordine che si verifica più volte nella stessa raccolta.
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...