Different types of Mapping in Nhibernate 2

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

$26.99    $13.50
by Aaron Cure | May 2010 | Open Source

NHibernate is an open source object-relational mapper, or simply put, a way to rapidly retrieve data from your database into standard .NET objects.

In this article by Aaron B. Cure, Author of NHibernate 2 Beginner's Guide, we will learn how to glue tables and classes that hold our data in the application

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

What is mapping?

Simply put, we need to tell NHibernate about the database that we created and how the fields and tables match up to the properties and classes we created. We need to tell NHibernate how we will be assigning Primary Keys, the data types that we will be using to represent data, what variables we will store them in, and so on. You could say this is one of the most important exercises we will perform in our pursuit of NHibernate. Don't worry though, it's pretty easy.

Types of mapping

There are two basic ways to map data for NHibernate: the traditional XML mapping in an hbm.xml file, or the newer "Fluent NHibernate" style, which is similar to the interface pattern introduced with the .NET 3.5 framework (see http://www.martinfowler.com/bliki/FluentInterface.html).

In both cases, we will create a document for each of our tables. We will map each field from our database to the property we created to display it in our class.

XML mapping

XML mapping is undoubtedly the most common method of mapping entities with NHibernate. Basically, we create an XML document that contains all of the information about our classes and how it maps to our database tables.

These documents have several advantages:

  • They are text files, so they are small
  • They are very readable
  • They use a very small number of tags to describe the data

The two biggest complaints about XML mapping is the verbosity of the text and that it is not compiled.

We can handle some of the verbosity by limiting the amount of data we put into the document. There are a number of optional parameters that do not absolutely need to be mapped, but that provide additional information about the database that can be included. We'll discuss more about that in the Properties section.

You should copy the nhibernate-mapping.xsd and nhibernate-configuration.xsd files from the NHibernate ZIP file into your Visual Studio schemas directory (that is C:\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\schemas\xml). This will give you IntelliSense and validation in the .NET XML editor when editing NHibernate mapping and configuration files.

Without compilation, when the database changes or the classes change, it's difficult to detect mismatches until the application is actually executed and NHibernate tries to reconcile the database structure with the mapping classes. While this can be an issue there are a number of ways to mitigate it, such as careful monitoring of changes, writing tests for our persistence layer, using a Visual Studio plugin, or using a code generation tool.

Getting started

The XML mapping document begins like any XML document, with an XML declaration. No magic here, just a simple xml tag, and two attributes, version and encoding.

<?xml version="1.0" encoding="utf-8" ?>

The next tag we are going to see in our document is the hibernate-mapping tag. This tag has an attribute named xmlns, which is the XML namespace that the NHibernate mapping file should be validated against. This is directly related to a version of NHibernate, as each version has its own XML namespace to cover changes in the mapping language.

We can also use this tag to define the namespace and assembly that the class we are mapping resides in. The opening and closing tags for the hibernate-mapping tag are as shown in the following code snippet:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="BasicWebApplication.Common.DataObjects"
assembly="BasicWebApplication">
</hibernate-mapping>

These three properties within the hibernate-mapping tag make up the basic XML mapping document.

Classes

The next tag we need to define in our document is the class tag. This is a KEY tag, because it tells NHibernate two things—the class this mapping document is meant to represent and which table in the database that class should map to.

The class tag has two attributes we need to be concerned with—name and table

<class name="" table="">
</class>

The name attribute contains the fully-qualified POCO (or VB.NET) class that we want to map to, including the assembly name.

While this can be specified in the standard fully-qualified dotted class name, a comma, and then the assembly name, the preferred method is to define the namespace and assembly in the <hibernate-mapping> tag, as shown in the previous code.

The table attribute specifies the table in the database that this mapping file represents. It can be as simple as the name of the table Address or as complex as needed to adequately describe the table.

If you need to include the owner of the table, such as dbo.Address, then you can add the schema attribute as follows:

schema="dbo"

If we were going to map the Address class in our application to the Address table in the database, then we would use a tag as follows:

<class name="Address" table="Address">
</class>

Technically, as the table name is the same as our class name, we could leave out the table attribute.

Properties

We can map properties from our class to fields in the database using the id tag and the property tag. These tags are for the standard fields in the database, not the Foreign Key fields. We'll get to those in a minute.

The id and property tags follow a standard pattern and have a number of optional parameters. They follow the basic format of defining the property on the class that they are mapping to and the data type that is used to represent that data. This will generally look as follows:

<property name="Address1" type="String">
<column name="Address1" length="255" sql-type="varchar"
not-null="true"/>
</property>

This is the fully-verbose method of mapping the properties, and the one I personally use. If something happens to your database, you can re-generate the database from this information. It's also very helpful when you are troubleshooting because all of the information about the data is right there.

Alternately, you can map the property as follows:

<property name="Address1" />

Both methods will provide the same mapping to NHibernate, but as I stated earlier, the more verbose method gives you a lot more flexibility.

One of the optional attributes that I generally use on the id and property tags is the type attribute. With this attribute I can tell NHibernate that I am using a particular type of data to store that information in my class. Adding this data type, our property tag would look as follows:

<property name="Address1" type="String" />

I also like to use the column tag, just to explicitly link the field with the property in the class, but that again is just preference. The previous code is completely adequate.

ID columns

The first property from our class that we want to map is the Id property. This tag has a number of attributes we can optionally set, but the simplest way we can map the Id property is as follows:

<id name="Id">
<generator class="hilo"/>
</id>

This tells NHibernate that we have a property in our class named Id which maps to a field in the database called Id and also that we use the hilo method to automatically generate a value for this field. Simple enough!

An optional attribute that I generally use on the id tag is the unsaved-value attribute. This attribute specifies what value should be returned in a new object before it is persisted (saved) to the database. Adding this attribute, as well as the type attribute we talked about, the code would look as follows:

<id name="Id" type="Int32" unsaved-value="null">
<generator class="hilo"/>
</id>

As long as our field is named Id in the database, we are good to go. But what if it was named id or address_id? This simply wouldn't handle it. In that case, we would have to add the optional column tag to identify it:

<id name="Id">
<column name="address_id"/>
<generator class="hilo"/>
</id>

Now we have mapped our address_id field from the database into a more standard Id property on our class. Some of the additional attributes that are commonly used on the column tag are as follows:

  • name: Define the name of the column in the database
  • length: The length of the field, as defined in the database
  • sql-type: The database definition of the column type
  • not-null: Whether or not the database column allows nulls. not-null="true" specifies a required field

Again, these optional attributes simply allow you to further define how your database is created. Some people don't even define the database. They just define the hbm.xml files and use the NHibernate.Tool.hbm2ddl to create a SQL script to do this work!

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

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

Mapping our types

Let's take a few minutes and map the basic fields from the OrderHeader table we created earlier. What we really need to do is map all of the "standard" fields (ints, varchars, datetimes, decimals, and so on) to their .NET counterparts , A touch of class.

Time for action – mapping basic types

Take a look at the following OrderHeader table. We need to map the Number, OrderDate, ItemQty, and Total fields into our OrderHeader class.

Different types of Mapping in NHibernate

  • Open the OrderHeader class . This will be either OrderHeader.cs or OrderHeader.vb. We will use this file for reference while we create our mapping document. Your class should look as follows:

    using System;
    using System.Collections.Generic;
    using System.Text;
    namespace Ordering.Data
    {
    public class OrderHeader
    {
    #region Constructors
    public OrderHeader() { }
    public OrderHeader(string Number, DateTime OrderDate,
    int ItemQty, decimal Total, Contact BillToContact,
    Contact ShipToContact, Address BillToAddress,
    Address ShipToAddress): this()
    {
    this.Number = Number;
    this.OrderDate = OrderDate;
    this.ItemQty = ItemQty;
    this.Total = Total;
    this.BillToContact = BillToContact;
    this.ShipToContact = ShipToContact;
    this.BillToAddress = BillToAddress;
    this.ShipToAddress = ShipToAddress;
    }
    #endregion
    #region Properties
    private int _id;
    public virtual int Id
    {
    get { return _id; }
    set { _id = value; }
    }
    private string _number;
    public virtual string Number
    {

    get { return _number; }
    set { _number = value; }
    }
    private DateTime _orderDate;
    public virtual DateTime OrderDate
    {
    get { return _orderDate; }
    set { _orderDate = value; }
    }
    private int _itemQty;
    public virtual int ItemQty
    {
    get { return _itemQty; }
    set { _itemQty = value; }
    }
    private decimal _total;
    public virtual decimal Total
    {
    get { return _total; }
    set { _total = value; }
    }
    private IList<OrderItem> _orderItems;
    public virtual IList<OrderItem> OrderItems
    {
    get { return _orderItems; }
    set { _orderItems = value; }
    }
    private Contact _billToContact;
    public virtual Contact BillToContact
    {
    get { return _billToContact; }
    set { _billToContact = value; }
    }
    private Contact _shipToContact;
    public virtual Contact ShipToContact
    {
    get { return _shipToContact; }
    set { _shipToContact = value; }

    }
    private Address _billToAddress;
    public virtual Address BillToAddress
    {
    get { return _billToAddress; }
    set { _billToAddress = value; }
    }
    private Address _shipToAddress;
    public virtual Address ShipToAddress
    {
    get { return _shipToAddress; }
    set { _shipToAddress = value; }
    }
    #endregion
    }
    }

    Or in VB.NET, it will look as follows:

     

    Public Class OrderHeader
    #Region "Constructors"
    Public Sub New()
    End Sub
    Public Sub New(ByVal Number As String, ByVal OrderDate As _
    DateTime, ByVal ItemQty As Integer, ByVal Total _
    As Decimal, ByVal BillToContact As Contact, _
    ByVal ShipToContact As Contact, ByVal _
    BillToAddress As Address, ByVal ShipToAddress _
    As Address)
    Me.New()
    Me.Number = Number
    Me.OrderDate = OrderDate
    Me.ItemQty = ItemQty
    Me.Total = Total
    Me.BillToContact = BillToContact
    Me.ShipToContact = ShipToContact
    Me.BillToAddress = BillToAddress
    Me.ShipToAddress = ShipToAddress
    End Sub
    #End Region
    #Region "Properties"
    Private _id As Integer
    Public Overridable Property Id() As Integer
    Get
    Return _id
    End Get
    Set(ByVal value As Integer)
    _id = value
    End Set
    End Property
    Private _number As String
    Public Overridable Property Number() As String
    Get
    Return _number
    End Get
    Set(ByVal value As String)
    _number = value
    End Set
    End Property
    Private _orderDate As DateTime
    Public Overridable Property OrderDate() As DateTime
    Get
    Return _orderDate
    End Get
    Set(ByVal value As DateTime)
    _orderDate = value
    End Set
    End Property
    Private _itemQty As Integer
    Public Overridable Property ItemQty() As Integer
    Get
    Return _itemQty
    End Get
    Set(ByVal value As Integer)
    _itemQty = value
    End Set
    End Property
    Private _total As Decimal
    Public Overridable Property Total() As Decimal
    Get
    Return _total
    End Get
    Set(ByVal value As Decimal)
    _total = value
    End Set
    End Property
    Private _orderItems As IList(Of OrderItem)
    Public Overridable Property OrderItems() As IList_
    (Of OrderItem)
    Get
    Return _orderItems
    End Get
    Set(ByVal value As IList(Of OrderItem))
    _orderItems = value
    End Set
    End Property
    Private _billToContact As Contact
    Public Overridable Property BillToContact() As Contact
    Get
    Return _billToContact
    End Get
    Set(ByVal value As Contact)
    _billToContact = value
    End Set
    End Property
    Private _shipToContact As Contact
    Public Overridable Property ShipToContact() As Contact
    Get
    Return _shipToContact
    End Get
    Set(ByVal value As Contact)
    _shipToContact = value
    End Set
    End Property
    Private _billToAddress As Address
    Public Overridable Property BillToAddress() As Address
    Get
    Return _billToAddress
    End Get
    Set(ByVal value As Address)
    _billToAddress = value
    End Set
    End Property
    Private _shipToAddress As Address
    Public Overridable Property ShipToAddress() As Address
    Get
    Return _shipToAddress
    End Get
    Set(ByVal value As Address)
    _shipToAddress = value
    End Set
    End Property
    #End Region
    End Class
  • Before we get started, let's create a few folders to make our job a little easier.Right-click on your Ordering.Data project and click on Add New| Folder.

    Different types of Mapping in NHibernate

  • Let's name the folder Common, and we'll drag all of our existing classes (Address, Contact, OrderHeader, and OrderItem) into that folder. This will make it easier to find things as we get more files.
  • Using the same procedure, create a new folder called Mapping so we can add our hbm.xml mapping files. When you are done, it should look as follows:

    Different types of Mapping in NHibernate

  • Right-click on the Mapping folder and click Add New Item|.

    Different types of Mapping in NHibernate

  • In the Add New Item – Ordering.Data dialog box, select Data as the category, then XML File under the template. Name the template OrderHeader.hbm.xml and click on Add.

    Different types of Mapping in NHibernate

  • Once the new file has been created, it will open in the editor. It should look something like the following screenshot:

    Different types of Mapping in NHibernate

  • The first thing we want to do with our mapping file is to ensure that it gets compiled into our assembly so NHibernate can find it. Right-click on the OrderHeader.hbm.xml file and select Properties.

    Different types of Mapping in NHibernate

  • In the Properties dialog, drop down the Build Auction menu and select Embedded Resource. This will ensure that the file is compiled into our assembly.

    Different types of Mapping in NHibernate

  • Inside our OrderHeader.hbm.xml document, we want to add the actual mapping data. The first thing we need to add is our nhibernate-mapping element. This will become the root element for our document. Under the <?xml version="1.0" encoding="utf-8" ?> tag, add the hibernate-mapping tags. Your document should look as follows:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="Ordering.Data.OrderHeader",
    assembly="Ordering.Data">
    </hibernate-mapping>
  • The next element that we will need in our mapping document is the class element. This element lets NHibernate know which class in our assembly maps to which table in the database. Add a class tag to map the OrderHeader class to the OrderHeader table as follows:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name=" OrderHeader" table="OrderHeader">
    </class>
    </hibernate-mapping
  • Now, we need to map our Id field. Between the opening and closing class tags, add the following code to map our Id field, and let NHibernate know that it's an Identity field by using the native generator class:

    <class name=" OrderHeader " table="OrderHeader">
    <id name="Id">
    <generator class="hilo"/>
    </id>
    </class>
  • If you wish, you can also map the field with all the data required to generate the database, as follows:

    <id name="Id" type="Int32" unsaved-value="null">
    <column name="Id" length="4" sql-type="int" not-null="true"
    unique="true" index="PK_OrderHeader"/>
    <generator class="hilo" />
    </id>
  • Most programmers opt for the first syntax when they are handcoding, as it is much less to type! However, when I automatically generate these XML documents with a code generator, I opt to include the additional information to help me troubleshoot later (should something go wrong).

  • Next, we need to map our remaining properties into the class element. Add the Number, OrderDate, ItemQty, and Total properties as follows:

    <property name="Number" type="String"/>
    <property name="OrderDate" type="DateTime"/>
    <property name="ItemQty" type="Int32"/>
    <property name="Total" type="Decimal"/>
  • That should do it! Your OrderHeader.hbm.xml file should look as follows:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="Ordering.Data.OrderHeader, Ordering.Data"
    table="OrderHeader">
    <id name="Id">
    <column name="Id"/>
    <generator class="native"/>
    </id>
    <property name="Number" type="String"/>
    <property name="OrderDate" type="DateTime"/>
    <property name="ItemQty" type="Int32"/>
    <property name="Total" type="Decimal"/>
    </class>
    </hibernate-mapping>
  • What just happened?

    We created an hbm.xml mapping file for our OrderHeader table and included all of the non-Foreign Key fields. By mapping all of the fields, NHibernate now understands which fields from the database we are using in our classes.

    Summary

    In this article we've learned,how to glue tables and classes that hold our data in the application


    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: $26.99
    Book Price: $44.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

    Spring Persistence with Hibernate
    Spring Persistence with Hibernate

    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


    Your rating: None Average: 5 (1 vote)
    Many to one Problem by
    hi i have read and implemented ur book .thts grt :) but i dont knw why i m getting problem in implementing it in my project ,please check and locat my fault http://forums.asp.net/p/1612888/4126755.aspx#4126755

    Post new comment

    CAPTCHA
    This question is for testing whether you are a human visitor and to prevent automated spam submissions.
    3
    S
    g
    C
    h
    8
    Enter the code without spaces and pay attention to upper/lower case.
    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