Monday, October 19, 2009

Fluent Nhibernate

I have always been skeptical on ORMs. There are a lot of options out there... Nhibernate, LinqToSql, Entity Framework, etc. I have always found them to be lacking it some regard. LinqToSql and Entity Framework in my opinion especially have been a complete failure because they only have data driven applications in mind.

Even NHibernate which is a well known ORM and very flexible has it drawbacks. Its main drawback is that its very XML heavy. You have the power to design your model separate from your database but you are required to map all your entities and fields using XML to the relevant database tables and fields. Not something you want to manage in the long run....

But behold a new version of NHibernate is available. This is called Fluent NHibernate. They have removed the XML configuration and replaced it with mapper files (similar to Data Mappers for those who are familiar with the pattern) that uses LINQ to map properties to database fields.

An example below:

public class SessionAudit : Audit
{
public virtual Guid SessionIdentifier { get; set; }
public virtual string ChannelAddress { get; set; }
public virtual SessionAuditTypes SessionAuditType { get; set; }
}


Here we have a Session Audit entity. There is nothing special about the entity except that Fluent NHibernate requires you to mark the fields you want to map with the virtual keyword. The reason for this is that they override those properties to do the actual mapping.

Next we have the mapper file:

public class SessionAuditMap : ClassMap<SessionAudit>
{
public SessionAuditMap()
{
Id(x => x.Id);
Map(x => x.DateModified);
Map(x => x.ChannelAddress).Unique();
Map(x => x.SessionIdentifier).Column("Session_Id"); ;
Map(x => x.SessionAuditType).CustomType<int>();
References(x => x.RoyaltyAgreement);
HasMany(x => x.ShareAgreements)
.Cascade.All()
.Inverse();
}
}


As you can see this class will do the mapping for you. It inherits from the generic ClassMap namespace which lets Fluent NHibernate know that you want to map a specific entity. Next, in the constructor, you define the fields that you want to map. Pretty Straightforward. They include a lot of overrides for you to use in the mapping. As seen in the example this includes mapping to specific column names, having one (or many) references to other entities. It also allows cascading changes made to all entities.

You can also enforce unique constraints and also specify indexes and composite keys. Fluent NHibernate allows allows custom queries to be called and even stored procedures for those that are included to use them.

In an added benefit Fluent NHibernate allows you to export the schema to the database and create it for you. For those of you relying on TDD and unit tests this is especially helpful because you can focus clearly on the model without the worry of integration (and maintaining) and mapping to the database. This allows you also to start writing integration tests early in your development because setup and initialize of the database is done for you.

For those of you interested in patterns, Fluent NHibernate supports Identity Map and a basic form of Unit of Work (using the ITransaction namespace).

An example of persisting:

using (var session = _SessionFactory.OpenSession())
{
// populate the database
using (var transaction = session.BeginTransaction())
{
try
{
foreach (object entity in UpdatedObjects)
{
session.SaveOrUpdate(entity);
}
transaction.Commit();
return true;
}
catch (Exception ex)
{
transaction.Rollback();
}
}
}


There are certain situations you want to use ORMs and our team debated this concept and decided that you could use it with great success in situations where you have few reads and numerous updates. The only real scenario that you wont use an ORM is when doing high volume transactions (some where in the range of 100 per second or more). Even if you have a lot of reads you can get around it using the Command/Query seperation pattern. But that is all the the architecture design of your application. Just make sure you know what you are getting in to :).

Till next time... live as clean as you code.

No comments:

Post a Comment