NHibernate - Mapeamento de coleção
Neste capítulo, abordaremos como representar coleções. Existem diferentes tipos de coleções que podemos usar no NHibernate, como -
- Lists
- Sets
- Bags
Agora, da perspectiva do .NET, geralmente lidamos com listas ou como estruturas de dados muito simples, listas, dicionários. .NET não tem uma grande variedade de tipos de coleção diferentes. Então, por que o NHibernate precisa de todos esses tipos diferentes? Ele realmente volta para o banco de dados.
Lista
Uma lista é uma coleção ordenada de elementos que não são necessariamente exclusivos.
Podemos mapear isso usando o IList <T>.
Portanto, embora possamos convencionalmente ter uma lista de endereços e, do ponto de vista da aplicação, saibamos que os elementos são únicos, nada na lista nos impede de inserir elementos duplicados nessa lista.
Conjunto
Um conjunto é uma coleção não ordenada de elementos únicos. Se você tentar inserir 2 elementos duplicados em um conjunto, ele lançará uma exceção.
Não há nada específico no NHibernate sobre isso.
É apenas uma maneira conveniente de ter uma implementação de conjunto genérico. Se você estiver no .NET 4, pode usar o novoHashSet <T> para representá-los, mas na maioria dos aplicativos NHibernate, representamos isso é um ISet.
É um não ordenado, se você puxar de volta uma lista de endereços de um banco de dados ou uma lista de pedidos, você não sabe em que ordem eles estão vindo, a menos que você coloque um pedido específico por cláusula.
Portanto, em geral, os dados que você está retirando de um banco de dados são conjuntos.
Eles são coleções únicas de elementos não ordenados.
Bolsa
Outra coleção comum que veremos no mundo do banco de dados é uma bolsa, que é exatamente como um conjunto, exceto que pode ter elementos duplicados.
No mundo .NET, representamos isso por um IList.
Conjuntos são provavelmente os mais comuns, mas você verá listas e bolsas também, dependendo de sua aplicação. Vamos dar uma olhada em um abaixocustomer.hbm.xml arquivo do último capítulo em que as ordens de conjunto são definidas.
<?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 você pode ver, mapeamos a coleção de pedidos como um conjunto. Lembre-se de que um conjunto é uma coleção não ordenada de elementos únicos.
Agora, se você observar a classe Customer, verá que a propriedade Orders é definida com um ISet, conforme mostrado no programa a seguir.
public virtual ISet<Order> Orders { get; set; }
Agora, quando este aplicativo for executado, você verá a seguinte saída.
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 os itens na coleção não precisassem ser exclusivos, se você pudesse ter vários pedidos com a mesma chave primária ocorrendo várias vezes nesta coleção, isso seria melhor mapeado como uma bolsa, conforme mostrado no programa a seguir.
<bag name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</bag>
Agora, se você executar este aplicativo, obterá uma exceção porque se dermos uma olhada na classe do cliente, você notará que os pedidos são marcados como um ISet no código C #.
Portanto, também precisaremos alterar isso para IList e, aqui, precisaremos alterar de HashSet para List no construtor.
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();
}
}
Ao executar o aplicativo, você verá o mesmo comportamento. Mas agora podemos ter um pedido ocorrendo várias vezes na mesma coleção.
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...