NHibernate 2: Mapping relationships and Fluent Mapping

Exclusive offer: get 50% off this eBook here
NHibernate 2 Beginner's Guide

NHibernate 2 Beginner's Guide — Save 50%

Rapidly retrieve data from your database into .NET objects

€20.99    €10.50
by Aaron Cure | May 2010 | Open Source

In the previous article , we have covered how to glue tables and classes that hold our data in the application.

In this article by Aaron cure, author of Nhibernate 2 Beginner's Guide, we will discuss Mapping relationships and Fluent Mapping

(Read more interesting articles on Nhibernate 2 Beginner's Guide here.)

Relationships

Remember all those great relationships we created in our database to relate our tables together?. Basically, the primary types of relationships are as follows:

  • One-to-many (OTM)
  • Many-to-one (MTO)
  • One-to-one (OTO)
  • Many-to-many (MTM)

We won't focus on the OTO relationship because it is really uncommon. In most situations, if there is a need for a one-to-one relationship, it should probably be consolidated into the main table.

One-to-many relationships

The most common type of relationship we will map is a one-to-many (OTM) and the other way—many-to-one (MTO). If you remember, these are just two different sides of the same relationship, as seen in the following screenshot:

This is a simple one-to-many (OTM) relationship where a Contact can be associated with zero to many OrderHeader records (because the relationship fields allow nulls). Notice that the Foreign Key for the relationship is stored on the "many" side, ShipToContact_Id and BillToContact_Id on the OrderHeader table. In our mapping files, we can map this relationship from both sides.

If you remember, our classes for these objects contain placeholders for each side of this relationship. On the OrderHeader side, we have a Contact object called BillToContact:

private Contact _billToContact;
public Contact BillToContact
{
get { return _billToContact; }
set { _billToContact = value; }
}

On the Contact side, we have the inverse relationship mapped. From this vantage point, there could be SEVERAL OrderHeaders objects that this Contact object is associated with, so we needed a collection to map it:

private IList<OrderHeader> _billTOrderHeaders;
public IList<OrderHeader> BillTOrderHeaders
{
get { return _billTOrderHeaders; }
set { _billTOrderHeaders = value; }
}

As we have mapped this collection in two separate classes, we also need to map it in two separate mapping files. Let's start with the OrderHeader side. As this is the "many" side of the one-to-many relationship, we need to use a many-to-one type to map it. Things to note here are the name and class attributes. name, again, is the property in our class that this field maps to, and class is the "other end" of the Foreign Key relationship or the Contact type in this case.

<many-to-one name="BillToContact" class="Contact">
<column name="BillToContact_Id" length="4" sql-type="int"
not-null="false"/>
</many-to-one>

Just like before, when we mapped our non-relational fields, the length, sql-type, and not-null attributes are optional.

Now that we have the "one" side mapped, we need to map the "many" side. In the contact mapping file, we need to create a bag element to hold all of these OrderHeaders. A bag is the NHibernate way to say that it is an unordered collection allowing duplicated items. We have a name element to reference the class property just like all of our other mapping elements and a key child element to tell NHibernate which database column this field is meant to represent.

<bag name="BillToOrderHeaders" inverse="true
cascade="all-delete-orphan">
<key column="BillToContact_Id"/>
<one-to-many
class="BasicWebApplication.Common.DataObjects.OrderHeader,
BasicWebApplication"/>
</bag>

If you look at the previous XML code, you will see that the one-to-many tag looks very similar to the many-to-one tag we just created for the other side. That's because this is the inverse side of the relationship. We even tell NHibernate that the inverse relationship exists by using the inverse attribute on the bag element. The class attribute on this tag is just the name of the class that represents the other side of the relationship.

The cascade attribute tells NHibernate how to handle objects when we delete them. Another attribute we can add to the bag tag is the lazy attribute. This tells NHibernate to use "lazy loading", which means that the record won't be pulled from the database or loaded into memory until you actually use it. This is a huge performance gain because you only get data when you need it, without having to do anything. When I say "get Contact record with Id 14", NHibernate will go get the Contact record, but it won't retrieve the associated BillToOrderHeaders (OrderHeader records) until I reference Contact.BillToOrderHeaders to display or act on those objects in my code. By default, "lazy loading" is turned on, so we only need to specify this tag if we want to turn "lazy loading" off by using lazy="false".

Many-to-many relationships

The other relationship that is used quite often is the many-to -many (MTM) relationship. In the following example, the Contact_Phone table is used to join the Contact and Phone tables. NHibernate is smart enough to manage these MTM relationships for us, and we can "optimize out" the join table from our classes and just let NHibernate take care of it.

Just like the one-to-many relationship, we represent the phones on the Contact class with a collection of Phone objects as follows:

private IList<Phone> _phones;
public IList<Phone> Phones
{
get { return _ phones; }
set { _ phones = value; }
}

Mapping the MTM is very similar to the OTM, just a little more complex. We still use a bag and we still have a key. We need to add the table attribute to the bag element to let NHibernate know which table we are really storing the relationship data in. Instead of a one-to-many and a many-to-one attribute, both sides use a many-to-many element (makes sense, it is an MTM relationship, right?). The many-to-many element structure is the same as the one-to-many element, with a class attribute and a column child element to describe the relationship.

<bag name="Phones" table="Contact_Phone" inverse="false" lazy="true"
cascade="none">
<key>
<column name="Contact_Id" length="4" sql-type="int"
not-null="true"/>
</key>
<many-to-many class=" Phone">
<column name="Phone_Id" length="4" sql-type="int"
not-null="true"/>
</many-to-many>
</bag>

From the Phone side, it looks remarkably similar, as it's just the opposite view of the same relationship:

<bag name="Contacts" table="Contact_Phone" inverse="false"
lazy="true" cascade="none">
<key>
<column name="Phone_Id" length="4" sql-type="int"
not-null="true"/>
</key>
<many-to-many class=" Contact ">
<column name="Contact_Id" length="4" sql-type="int"
not-null="true"/>
</many-to-many>
</bag>

Getting started

This should be enough information to get us rolling on the path to becoming NHibernate superstars! Now that we have all of the primary fields mapped, let's map the Foreign Key fields.

Time for action – mapping relationships

If you look at the following database diagram, you will see that there are two relationships that need to be mapped, BillToContact and ShipToContact (represented by BillToContact_Id and ShipToContact_Id in the following screenshot).

Let's map these two properties into our hbm.xml files.

  1. Open the OrderHeader.hbm.xml file, which should look something as follows:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="Ordering.Data" assembly="Ordering.Data">
    <class name="OrderHeader" table="OrderHeader ">
    <id name="Id">
    <column name="Id"/>
    <generator class="hilo"/>
    </id>
    <property name="Number" type="String"/>
    <property name="OrderDate" type="DateTime"/>
    <property name="ItemQty" type="Int32"/>
    <property name="Total" type="Decimal"/>
    </class>
    </hibernate-mapping>
  2. After the Total property, just before the end of the class tag (</class>), add a many-to-one element to map the BillToContact to the Contact class.

    <many-to-one name="BillToContact" class="Ordering.Data.Contact,
    Ordering.Data">
    <column name="BillToContact_Id" />
    </many-to-one>
  3. Next, open the Contact.hbm.xml file, which should look as follows:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="Ordering.Data" assembly="Ordering.Data">
    <class name=" Contact " table="Contact">
    <id name="Id">
    <column name="Id"/>
    <generator class="hilo"/>
    </id>
    <property name="FirstName" type="String"/>
    <property name="LastName" type="String"/>
    <property name="Email" type="String"/>
    </class>
    </hibernate-mapping>
  4. After the Email property, just before the end of the class tag (</class>), add a one-to-many element to map the BillToOrderHeaders to the OrderHeader class.

    <bag name="BillToOrderHeaders" inverse="true" lazy="true"
    cascade="all-delete-orphan">
    <key column="BillToContact_Id"/>
    <one-to-many class="OrderHeader "/>
    </bag>
  5. That's it! You just mapped your first one-to-many property! Your finished Contact.hbm.xml class should look as shown in the following screenshot:

What just happened?

By adding one-to-many and many-to-one child elements to the bag tag, we were able to map the relationships to the Contact object, allowing us to use dotted notation to access child properties of our objects within our code.

Like the great cartographers before us, we have the knowledge and experience to go forth and map the world!

Have a go hero – flushing out the rest of our map

Now that you have some experience mapping fields and Foreign Keys from the database, why not have a go at the rest of our database! Start off with the Contact-to-Phone MTM table, and map the rest of the tables to the classes we created earlier, so that we will be ready to actually connect to the database

NHibernate 2 Beginner's Guide Rapidly retrieve data from your database into .NET objects
Published: May 2010
eBook Price: €20.99
Book Price: €34.99
See more
Select your format and quantity:

(Read more interesting articles on Nhibernate 2 Beginner's Guide here.)

Fluent mapping

While XML mapping is undoubtedly the most common mapping method, the fluent NHibernate method is gaining steam. This is a separate project from the main NHibernate project, and you can find out more information about it at http://fluentnhibernate.org/.

Some of the advantages of fluent mapping over XML mapping are as follows:

  • Compile-time mapping validation: XML is not evaluated by the compiler, so renaming properties in your classes or other errors in your hbm.xml mapping would not be detected until you actually run the application
  • Less verbose: XML by nature is fairly easy to read because of the number of characters it requires to produce even simple documents, but this makes for huge documents
  • Fewer repetitions: Instead of writing the same repetitive XML over and over, the fluent interface exposes the advantages of native code

Fluent NHibernate provides these advantages by moving your mappings from XML documents directly into your code. They're compiled along with your application! You can also use Fluent's configuration system to specify patterns to make your code simpler and more readable.

Remember the Address table we created for our Ordering system, shown in the following screenshot? Let's take a look at a fluent map for this table.

NHibernate2: Mapping relationships and Fluent Mapping

The traditional XML map for this table would look something like the following block of code:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="BasicWebApplication.Common.DataObjects.Address,
BasicWebApplication" table="Address">
<id name="Id" type="Int32" unsaved-value="null">
<column name="Id" length="4" sql-type="int" not-null="true"
unique="true" index="PK_Address"/>
<generator class="hilo" />
</id>
<property name="Address1" type="String">
<column name="Address1" length="255" sql-type="varchar"
not-null="true"/>
</property>
<property name="Address2" type="String">
<column name="Address2" length="255" sql-type="varchar"
not-null="false"/>
</property>
<property name="City" type="String">
<column name="City" length="255" sql-type="varchar"
not-null="true"/>
</property>
<property name="State" type="String">
<column name="`State`" length="2" sql-type="varchar"
not-null="true"/>
</property>
<property name="Zip" type="String">
<column name="Zip" length="12" sql-type="varchar"
not-null="true"/>
</property>
<many-to-one name="Contact"
class="BasicWebApplication.Common.DataObjects.Contact,
BasicWebApplication">
<column name="Contact_Id" length="4" sql-type="int"
not-null="false"/>
</many-to-one>
<bag name="BillToOrderHeaders" inverse="true" lazy="true"
cascade="all-delete-orphan">
<key column="BillToAddress_Id"/>
<one-to-many class="BasicWebApplication.Common.DataObjects.
OrderHeader, BasicWebApplication"/>
</bag>
<bag name="ShipToOrderHeaders" inverse="true" lazy="true"
cascade="all-delete-orphan">
<key column="ShipToAddress_Id"/>
<one-to-many class="BasicWebApplication.Common.DataObjects.
OrderHeader, BasicWebApplication"/>
</bag>
</class>
</hibernate-mapping>

You have to admit that the code is pretty readable, but it sure is verbose! Do I really need 35 lines of code to describe classes that are already contained in my application? Wouldn't it be cleaner to just write it as follows?

public class AddressMap : ClassMap<Address>
{
WithTable("Address");
Id(x => x.Id);
Map(x => x.Address1).WithLengthOf(255);
Map(x => x.Address2).WithLengthOf(255).Nullable();
Map(x => x.City).WithLengthOf(255);
Map(x => x.State).WithLengthOf(2);
Map(x => x.Zip).WithLengthOf(12);
References(x => x. Contact).Nullable();
HasMany(x => x.BillToOrderHeaders).Inverse().Cascade.All();
HasMany(x => x.ShipToOrderHeaders).Inverse().Cascade.All();
}

The preceding code is definitely more readable, if only because it's shorter.

The advantages of the fluent interface are many, from simpler compiled code to being able to fit the entire table mapping onto one page.

If you are looking for an even simpler method, and if you can follow a couple of simple conventions when you create your database, then you can use the "Auto Persistence Model" to automatically map your data, and you don't need to write any mapping code at all! This method is perfect if you have control of your database structure (you are the database administrator or at least can change field names in the database if you want them changed in your classes). All you have to do is create your tables, create your object classes (POCOs), and tell Fluent to auto-map the tables to the classes because they have the same name.

Better yet, just create your POCOs, and use NHibernate to generate your database and Fluent NHibernate to map it!

Summary

Wow, we made a lot of progress in this article We talked more about mapping in a few pages than most people learn in a lifetime.

Specifically, we covered:

  1. How to map the basic elements of a table into a class
  2. Mapping OTM and MTM relationships
  3. The basics of Fluent mapping

If you have read this article you may be interested to view:

NHibernate 2 Beginner's Guide Rapidly retrieve data from your database into .NET objects
Published: May 2010
eBook Price: €20.99
Book Price: €34.99
See more
Select your format and quantity:

About the Author :


Aaron Cure

Aaron Cure is an avid developer, instructor, and innovator. During his 10 years in the military as a linguist and a satellite communications repair technician, he learned that his real love was computer programming.

After various throes with PHP, Classic ASP, VB, and a brief encounter with Java/JSP, he found a real passion for the .NET framework. After searching for a "better way" to carry out database storage and retrieval, Aaron stumbled across the NHibernate framework.

Unsatisfied with the options for interacting with this great framework, he founded the NHibernate Generation project (nhib-gen) on SourceForge to reduce the "barrier to entry" for most developers.

Aaron and his family run a small consulting and web hosting company doing web design and custom software development for various organizations across the country. One of their more interesting projects has been software to control laser cutting machines.

In his spare time, he also enjoys developing projects with his daughters, using everything from Lego NXT (using C# and Bluetooth communications) to the Microchip PIC platform (using JAL and USB). He also collects and restores classic farm tractors, engines, and farm equipment, as well as semi trucks and trailers. He and his family display them at tractor shows, parades, schools, and various other community events.

Books From Packt


Refactoring with Microsoft Visual Studio 2010
Refactoring with Microsoft Visual Studio 2010

Mastering phpMyAdmin 3.1 for Effective   MySQL Management
Mastering phpMyAdmin 3.1 for Effective MySQL Management

ASP.NET Data Presentation Controls Essentials
ASP.NET Data Presentation Controls Essentials

High Availability MySQL   Cookbook
High Availability MySQL Cookbook

ASP.NET 3.5 Application Architecture and Design
ASP.NET 3.5 Application Architecture and Design

VSTO 3.0 for Office 2007 Programming
VSTO 3.0 for Office 2007 Programming

C# 2008 and 2005 Threaded   Programming: Beginner's Guide
C# 2008 and 2005 Threaded Programming: Beginner's Guide

MySQL 5.1 Plugins Development
MySQL 5.1 Plugins Development


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software