I started learning about Fluent NHibernate the other day.
Where I hope NHibernate will help me:
There is a lot of redundant data modeling and data mapping code that has to be created for enterprise applications and this really seems to be a great way to hit the ground running and rapidly develop a quick-hit enterprise or single instance web application. As I said in my previous post: We had to develop an app within 2 days (roughly 3-4 team-work-days) fueled by massive amounts of carbonated caffeine and fat content enriched edibles. This meant speed and extreme focus on customer use-case over creating architecture was important. Since it was low concurrent user volume there wasn’t need to worry about scaling up or out on this.
My concerns & objectives going into NHibernate
Learning the ORM and getting comfortable with it (this post is the second part of that for me)
Dealing with Polymorphism in objects (Such as different types of bank accounts)
Dealing with lots of records or large collections (Such as bank transaction history)
Dealing with deep hierarchies or large object graphs (Such as bank customer records)
Where it fits into horizontally scalable applications on a scale of millions of concurrent users
Up till now
I was able to get a modest FluentNHibernate example project running that created some referenced tables and filled them with data. I covered utilizing the config file to do the connection string and how to exportSchema to do database creation.
Today’s Post
I’m going to touch on some of the early items from the ‘playing with cats example’. Ok first step, let’s get some simple mapping on our cat with FN (ill use that now for Fluent NHibernate since I’m tired of typing it).
public class CatMapping : ClassMap<Cat>
{
public CatMapping()
{
Id(c => c.Id)
.GeneratedBy
.UuidHex("N")
/* See Guid.ToString() for details
* http://msdn.microsoft.com/en-us/library/97af8hh4.aspx
* */
.Length(32);
Map(c => c.Name).Length(16);
Map(c => c.Sex).Nullable();
Map(c => c.Weight).Nullable();
Map(c => c.Height).Nullable();
Version(c => c.Version);
References(c => c.Father);
}
}
As you can See I added a column for height, added a version number for long running transactions to utilize the optimistic offline lock functionality in NHibernate. Also I had to do a bit of searching to find out how to use the UuidHex method. Basically it creates a string column that is the output of Guid.ToString(string format).
The cat entity (poco) looks like this:
public class Cat {
public virtual string Id { get; set; }
public virtual string Name { get; set; }
public virtual char Sex { get; set; }
public virtual float Weight { get; set; }
public virtual int Version { get; set; }
public virtual float Height { get; set; }
public virtual Cat Father { get; set; }
}
Generating and updating the Database Schema or DDL
I have a few things to explain before I show the code… I used an IoC container for this. Specifically, I used NInject because I love it J If you check out the NHibernate documentation then that should give you enough information to understand what’s going on in this code:
Working from the front to the back of the Database Creation webform/button:
The button Handler
Nothing fancy here… the button exports the schema to the database from the Configuration we’ve created… (Down further). The response.Write reference is an Action<string> that will write the generated DDL to the response for viewing. The true says: ‘yes, please export this in addition to outputting to screen go ahead and run it’
protected void Button1_Click(object sender, EventArgs e)
{
new SchemaExport(NHibernateHelper.Configuration)
.Create(Response.Write, true);
}
The NHibernate Helper (relevant code)
public sealed class NHibernateHelper {
private const string NHibernateSessionKey = "nhibernate.context_session";
private static ISessionFactory SessionFactory
{
get { return IoCRoot.Get<ISessionFactory>(); }
}
public static Configuration Configuration
{
get { return IoCRoot.Get<Configuration>(); }
}
/*ETC ETC…. same as nhibernate docs mostly except I changed the session key name. I didn’t like the word “Current” when referring to session. It’s the current context and the context has the session… so it would be a context session. Ironic coming from database people they’d have this WRONG ;) J J*/
The IoCRoot global class
This little guy will hold our NInject kernel and control which modules to load at construction/startup
public static class IoCRoot {
private static IKernel _kernel;
static IoCRoot()
{
Startup();
}
public static void Startup()
{
_kernel = new StandardKernel();
_kernel.Load<NHibernateModule>();
}
public static T Get<T>()
{
return _kernel.Get<T>();
}
}
The NHibernate Module to get the IoC container ready
Our ninject module controls what bindings we map to the IOC container. In this case a SessionFactory and a Configuration so we can pull those up whenever we want since they are application specific instances or global I’ve utilized my NInject version of the singleton pattern by using ToConstant() and providing an instance. Or so I hope J public class NHibernateModule : NinjectModule
{
private readonly ISessionFactory _sessionFactory;
private readonly Configuration _configuration;
public NHibernateModule()
{
_configuration = Fluently.Configure()
.Database(
MsSqlConfiguration .MsSql2008
.ConnectionString(c =>
c.FromConnectionStringWithKey("connectionStringKey")
)
)
.Mappings(m =>
m.FluentMappings
.AddFromAssemblyOf<NHibernateModule>()
)
.BuildConfiguration();
_sessionFactory = _configuration.BuildSessionFactory();
}
public override void Load()
{
Bind<ISessionFactory>().ToConstant(_sessionFactory);
Bind<Configuration>().ToConstant(_configuration);
}
}
OK awesome. We have our database now… but let’s say we wanted to add or remove columns! Yikes…
Updating Schema or DDL
We simply use SchemaUpdate. Same thing as SchemaExport with Response.Write and the Boolean.
protected void Button1_Click(object sender, EventArgs e)
{
new SchemaUpdate(NHibernateHelper.Configuration)
.Execute(Response.Write, true);
}
Making cats Just follow their guide: http://nhforge.org/doc/nh/en/index.html
Querying Cats
Same, follow their guide… nothing special there imo.
Finding 1 Cat
It seemed like their guide was out of date… here is what I came up with to select a cat by ID:
oneCat = session.CreateQuery("from Cat as cat where cat.Id = :id")
.SetString("id",IdVariable)
.UniqueResult<Cat>();
Finding all the cats
Again… it was out of date or different than I had to write with FH
List<Cat> cats = new List<Cat>();
session.CreateQuery("from Cat").List(cats);
In closing
The arrangement of everything is quite good, FH makes things way easier than xml config files (in my opinion, especially with resharper and lambdas). I’m bothered by the nuisance of the ‘second query language’ that I have to learn to use nhibernate... but maybe Linq To NHibernate might help
Source Code