Following up on my last post and on reading NHibernate 3.0 Cookbook I decided to download the latest NHibernate bits (v. 3 CR1), and do a comparison to Microsofts Entity Framework.
NHibernate and Entity Framework are what most developers reguard as the top Object Relational Mappers out there. So looking at how they stack up is pretty important in order to be able to choose the right ORM for a given project.
Even though most of us was probably taught that we should build a datalayer where the technology can be replaced, it turnes out that very few have ever done it. Those who have in my experience never describe it as painless. So in most cases we end up sticking to the ORM we choose to start with.
My comparison looks at NHibernate 3, and EF feature CTP 4 or Magic Unicorn edition as Scott Hanselman has named it. Even though the EF version is just a CTP, this is the point where I personally start taking it seriously, with the addition of code-first.
Setting up the ORM
First thing I looked at was what it takes just to get started. In this field EF has an natural advantage because as part of “the .NET package”, it actually doesn't require you to do anything.
NHibernate on the other hand requires you to go through a few steps.
- Download NHibernate
- Download Fluent NHibernate sourcecode
- Open the FluentnNibernate project.
- Change references to use the newest version of NHibernate in the FluentNHibernate project, and exclude the other projects.
- Compile the FluentNhibernate project.
- Add the files and reference the dlls of NHibernate and Fluent NHibernate in your project.
This should become easier with NuGet - but for now it is still a CTP so it’s fair to asume that most will probably go through this process for now.
Some might say "Hey, you don't absolutely need Fluent NHibernate", and while this is true I would in reallity not use NHibernate without it. Choosing to do mappings as XML requires a degree of self-hatred I am simply not capable of. If you don’t mind the xml – go ahead and only do steps 1 and 6.
I might be throwing a few holy handgranades here and for the rest of the post – but it’s my post so it reflects my honest oppinions.
Concluding on the basic setup is pretty much a nobrainer, because Entity Framework get a free win by just being there. To be fair I do think it will be simple to get going when NuGet is finished.
Configuration and defining your mappings
Now that we are ready to get started for real, we have a choise to make on how we wish to do out mapping between the relational database and the object-model.
Entity Framework configuration
With the Entity Framework we can do Database-first, Model-first or Code-first out of the box. This is actually very nice because it allows you to choose your approach depending on if you have a database already, and if you are a modelling or coding kind of guy.
Personally I think the “truth is in the code” – so I would almost always have code be the center of operations. Also the edmx file that you add to model in a designer generates xml – which I am not so fond of.
Below you see an example of what it takes to implement your own DbContext. It’s one of those things that are easy to get started with, but it takes some time to really master and know all the tricks.
public class CompanyCatalog : DbContext
{
public CompanyCatalog() : base("TestDB"){}
public DbSet<Company> Companies { get; set; }
public DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Company>().HasKey(b => b.Id);
modelBuilder.Entity<Company>().Property(b => b.Name).IsRequired();
modelBuilder.Entity<Company>().HasMany(a => a.Employees);
}
}
The call to IsRequired will be reflected in the database if you have EF generate it for you – making the column not allow null. Otherwise this would work even without that line of code, because it is based on the convention that properties map directly to columns in the database. If you wish to have a property that is not reflected you can from the next CTP use the StoreIgnoreAttribute on the property.
With this in place you can start using the CompanyCatalog as soon as you define the connection to use, which can be done like so if you are using SQl server:
Database.DefaultConnectionFactory =
new SqlConnectionFactory("connectionString goes here");
It defaults to creating the database for you if it does not exist, which can be overwritten by calling SetInitializer with an instance of RecreateDatabaseIfModelChanges, AlwaysRecreateDatabase or your own implementation.
NHibernate configuration
With NHibernate you always start with a session object, that has generic methods to access each entity/tabel as the root. This means that you wont have to write plumbing code like above, but also that you don’t have the option of modelling the session/context except by wrapping it.
Configuration can be done either with XML, which I already distanced myself from, or you can use libraries like Fluent NHibernate or ConfORM to do it in code. Personally my experience is with Fluent NHibernate and it is my impression that it is most widely used. Configuring Fluent NHibernate mappings is done with a class per entity like so:
public class CompanyMap : ClassMap<Company>
{
public CompanyMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Employees)
.Cascade.AllDeleteOrphan().Inverse();
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id);
Map(x => x.Name);
References(x => x.Company);
}
}
With Fluent NHibernate you map each property, and you have to configure eg. one-to-many in both ends of the relationship. The alternativt is to use AutoMapping, where you setup conventions for everything instead of writing mappings – which can be combined with maps for the special cases.
With the mappings in place you can create an ISessionFactory fluently like this:
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ConnectionString(“connectionString goes here”))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Employee>())
.BuildSessionFactory();
}
I have been using AutoMapping quite a bit, and it is really nice with the whole convention over configuration approach, but some times you need the extra control that you have when doing the mappings yourself. If you wish you can combine the two, which gives you the best of both worlds.
No matter which approach you take with NHibernate it can generate the database schema for you – it just takes a couple of lines of code, and I woulde recommend this for green field projects.
Summing up
Now we have all we need to start querying our datamodel. The two methods of configuration are a little different in their approach, but both are easy to grasp but difficult to master. Which is better is proabably a matter of personal preference in the vast majority of usecases. For those who like that kind of stuff Entity Framework probably wins out by giving you the option to use a designer which will help you get started quickly when you have an existing database.