7 min read

(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 FilesMicrosoft Visual Studio 9.0Common7Packagesschemasxml). 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 ><hibernate-mapping
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!

LEAVE A REPLY

Please enter your comment!
Please enter your name here