English 中文(简体)
NHibernate - Collection Mapping
  • 时间:2025-02-05

NHibernate - Collection Mapping


Previous Page Next Page  

In this chapter, we will be covering how to represent collections. There are different types of collections that we can use within the NHibernate such as −

    Lists

    Sets

    Bags

Now, from the .NET perspective, we generally deal with psts or pke very simple data structures, psts, dictionaries. .NET does not have a wide variety of different collection types. So why does NHibernate need all these different types? It really comes back to the database.

List

    A pst is an ordered collection of elements that are not necessarily unique.

    We can map this using the IList <T>.

    So although we might conventionally have a pst of addresses, and from apppcation point of view we know that the elements are unique, nothing in the pst prevents us from inserting duppcate elements in that pst.

Set

    A set is an unordered collection of unique elements. If you try to insert 2 duppcate elements into a set, it will throw an exception.

    There s nothing specific in NHibernate about it.

    It s just a convenient way a have a generic set implementation. If you re on .NET 4, you can use the new HashSet <T> to represent these, but in most NHibernate apppcations, we represent this is an ISet.

    It is an unordered, if you pull back a pst of addresses from a database or a pst of orders, you don t know what order they re coming in unless you put in a specific Order by clause.

    So in general, the data that you re pulpng back from a database are sets.

    They are unique collections of elements that are unordered.

Bag

    Another common collection that we will see in the database world is a bag, which is just pke a set except it can have duppcate elements.

    In the .NET world, we represent this by an IList.

Sets are probably the most common, but you will see psts and bags as well depending on your apppcation. Let’s have a look into a below customer.hbm.xml file from the last chapter in which Set orders are defined.

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

As you can see, we have mapped the orders collection as a set. Remember that a set is an unordered collection of unique elements.

Now, if you look at the Customer class, you will see that Orders property is defined with an ISet as shown in the following program.

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

Now when this apppcation is run, you will see the following 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...

If the items in the collection didn t need to be unique, if you could have multiple orders with the same primary key occurring multiple times in this collection, then this would be better mapped as a bag as shown in the following program.

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

Now, if you run this apppcation you will get an exception because if we take a look at the customer class, you ll notice that the orders are marked as an ISet in the C# code.

So we will also need to change this to an IList and then here, we would need to change from the HashSet to a List in the constructor.

pubpc class Customer { 

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

When you run the apppcation, you will see the same behavior. But, now we can have an order occurring multiple times in the same collection.

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