NHibernate mapping possibilities

NHibernate mapping possibilities

I prepare currently a new talk about NHibernate. In this talk I’ll show the different mapping possibilities with NHibernate. To demonstrate the three possibilities (and a fourth one) I chose a quite simple model: I implement three classes Cat, Dog and Bird an for each one I chose a different mapping approach. For my little sample application I used NHibernate 2.1.0, NHibernate.Mapping.Attributes 2.1.0 and Fluent NHibernate 1.0.0.545.

NHibernate classic style – XML-Files
For the class Cat I chose to use the classic way to map the class.
[code language=”csharp”]
public class Cat
{
private string id;
private string name;
private char sex;
private float weight;

public virtual string Id
{
get { return id; }
set { id = value; }
}

public virtual string Name
{
get { return name; }
set { name = value; }
}

public virtual char Sex
{
get { return sex; }
set { sex = value; }
}

public virtual float Weight
{
get { return weight; }
set { weight = value; }
}
}
[/code]
And the XML-File Cat.hbm.xml looks like:
[code language=”xml”]
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernateTest.Domain" assembly="NHibernateTest">
<class name="Cat" table="Cat">
<id name="Id">
<column name="CatId" sql-type="char(32)"/>
<generator class="uuid.hex" />
</id>
<property name="Name">
<column name="Name" length="16" not-null="true" />
</property>
<property name="Sex" />
<property name="Weight" />
</class>
</hibernate-mapping>
[/code]
This approach has different problems: You couldn’t easily refactor your POCOs, you have to adapt the hbm.xml files too. Another problem is that you write your entity twice: in C# and in XML, so there is a lot of noise. This is the entry point for code generation, but it isn’t a real solution, it is just a workaround to handle the necessary XML file correctly and to reduce errors by manual writing.

NHibernate.Mapping.Attributes
For the class Dog I prefer the attributes to map the class. In JPA it is my preferred way for simple and small projects, so I was very interested how they ported this approach to .Net.
[code language=”csharp”]
[Class(NameType = typeof(Dog))]
public class Dog
{
private Guid id;
private string strName;

[Id(0,
Column = "ID",
Name = "ID",
TypeType = typeof(Guid),
UnsavedValue = "(00000000-0000-0000-0000-000000000000)"
)]
[Generator(1, Class = "guid.comb")]
public virtual Guid ID
{
get { return id; }
private set { id = value; }
}

[Property(0, Column = "Name",
Name = "Name",
TypeType = typeof(string),
Length = 50,
NotNull = false
)]
public virtual string Name
{
get { return strName; }
set { strName = value; }
}
}
[/code]
Without the property NameType in the Class-attribute the sample doesn’t run. Another thing which disturbs me is the noise in the code by the attributes. It isn’t a clean POCO approach, also because the needed specific using statements.

Fluent NHibernate
Finally there is a third approach how to map a class. To demonstrate this possibility a use the Bird class:
[code language=”csharp”]
public class Bird
{
private Guid id;
private string strName;

public virtual Guid ID
{
get { return id; }
private set { id = value; }
}

public virtual string Name
{
get { return strName; }
set { strName = value; }
}
}
[/code]
For the mapping you have to use an additional class, which looks like that:
[code language=”csharp”]
public class BirdMapping : ClassMap<Bird>
{
public BirdMapping()
{
Id(x => x.ID);
Map(x => x.Name);
}
}
[/code]
This approach is really interesting. You separate your mapping from your entity, but the mapping is written in the same language like the entity itself. So you can profit of the refactor features of your IDE or of an additional tool like Resharper.

Use all together in the same project
I tried to run all the three possibilities in one project and I used a factory method to create the NHibernate configuration instance. This method looks like that:
[code language=”csharp”]
public static Configuration CreateConfiguration()
{
Configuration config = new Configuration();
config.Configure();

// XML-Files
config.AddAssembly(Assembly.GetExecutingAssembly());

// Attributes
HbmSerializer.Default.Validate = true; // Enable validation (optional)
HbmSerializer.Default.Serialize(System.Environment.CurrentDirectory, Assembly.GetExecutingAssembly());
config.AddDirectory(new DirectoryInfo(System.Environment.CurrentDirectory));

// Fluent
config = Fluently.Configure(config).Mappings(m => m.FluentMappings.AddFromAssemblyOf<Program>()).BuildConfiguration();

return config;
}
[/code]
In a real world application I wouldn’t recommend a such configuration. An architect should decide which mapping approach is adequate. But this code snippet demonstrate that it is possible to use all three mapping possibilities at the same time.

The secret fourth possibility
When I study NHibernate Fluent I saw on their wiki the possibility to use their Auto Mapping.
[code language=”csharp”]
private static Configuration CreateAutoConfiguration()
{
var config = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(@"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Test.mdf;Integrated Security=True;User Instance=True")
.ShowSql())
.Mappings(m => m.AutoMappings.Add(AutoMap
.Assembly(Assembly.GetExecutingAssembly())
.Where(t => t.Namespace == "NHibernateTest.Domain")))
.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(false, true))
.BuildConfiguration();

return config;
}
[/code]
The other three possibilities are a little bit different: there you define the mapping for each entity, which is more or less the opposite. You map by default all your entities by convention over configuration and only the exceptions have to be declared explicitly. Note that it is even possible to generate the DB schema with the ExposeConfiguration method.
For greenfield applications or prototypes it is a great way to map your entities, but for brownfield applications it is much harder to use. This is the case when you couldn’t discover a pattern in the database or in the entities, which you want to map. In a such scenario I would prefer one of the three other possibilities.

5 thoughts on “NHibernate mapping possibilities

  1. Pingback: Twitted by jbandi
  2. Pingback: Twitted by ajlopez

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.