Fluent Sharp NHibernate Persistence Configuration, or “How to build credibility through OSS name dropping”
For those of you skimming your RSS reader, I'll help you filter because I suspect my target audience is narrow with this one. This post deals with using the Fluent NHibernate IPersistenceConfigurer with Sharp Architecture.
The hillbilly is a-codin’ agin! And back with Sharp Architecture which I had all but abandoned in favour of Repeaters and ItemCommands and various other monsters used to frighten young ASP.NET developers. (“Eat all your vegetables, Johnny, or tonight, when you’re fast asleep, THE VIEWSTATE OGRE WILL EXPAND INSIDE YOUR CLOSET UNTIL IT BLOWS UP ALL YOUR BROWSERS!!!”). Ah, it’s good to back in the realm of geek jokes that will surely embarrass my children at some future date…
Much has happened in the Sharp Architecture world since I last visited. And to Fluent NHibernate, of which Sharp takes much advantage. It is now possible to work with NHibernate entirely without XML through the magic of fluent interfaces. Something that appeals to me aesthetically though it’s not a position I’ll defend to the death, or even to the slightly bruised.
Typically, NHibernate can be configured as follows:
var config = new Configuration( ); config.Configure( pathToNHConfigFile ); var sessionFactory = config.BuildSessionFactory();
Note that the parameter to Configure is optional. It appears that if one isn’t provided, it will default to looking for a file called NHibernate.config.xml. Though judging by how quickly things are changing, that may not be true by the time I click Publish.
The alternative with Fluent NHibernate is as follows:
var config = Fluently.Configure( ) .Database( MsSqlConfiguration.MsSql2005 .ConnectionString( c => c.FromConnectionStringWithKey("mainConnection") ) .ShowSql( ) .ProxyFactoryFactory( "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" ) ); var sessionFactory = config.BuildSessionFactory( );
In this case, you don’t even need an NHibernate Configuration object. Fluent NH looks to be doing all the work behind the scenes. All in all, it’s pretty clean and clear, save for that ProxyFactoryFactory call which may make sense to someone who has been actually following NH development. Personally, it required much BinGoogling to figure out that I even needed it.
It’s possible to get lost in the options though. Fluently.Configure( ) takes an optional NHibernate Configuration object, which presumably could be configured via a config file. And you can add mappings to the NHibernate Configuration *and* the Fluent NH Configuration. It’s not mind-bogglingly circular but it does add an element of fun when you’re prone to just bang away without putting any thought into it.
This is where I segue back to SharpArchitecture. Sharp has supported Fluent NH for a while now with the class mappings. It also provides a nice interface for easily configuring NHibernate through some overloaded Init methods. But none of them supported the Fluent NH configuration API, likely because it’s relatively new.
So at some point, another overload was created that took a Fluent NH IPersistenceConfigurer object, which contains the details about the NH configuration (e.g., the MsSqlConfiguration object above). However, it doesn’t account for situations where you provide an IPersistenceConfigurer but no config file. That is, the config file was still required even though you don’t need it.
A patch is under evaluation to fix this so that something like the following will soon be possible:
var configuration = MsSqlConfiguration.MsSql2005 .AdoNetBatchSize(500) .ShowSql() .ConnectionString(c => c.FromConnectionStringWithKey("main")) .ProxyFactoryFactory("NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle"); NHibernateSession.Init(webSessionStorage, new string[] { Server.MapPath("~/bin/TingsForSale.Data.dll") }, new AutoPersistenceModelGenerator().Generate(), null, null, null, configuration);
Until then, the only way to use the IPersistenceConfigurer aspect of Sharp Architecture is to either: a) provide a dummy config file, or b) mimic the code in NHibernateSession.Init like so:
var configuration = MsSqlConfiguration.MsSql2005 .AdoNetBatchSize(500) .ShowSql() .ConnectionString(c => c.FromConnectionStringWithKey("main")) .ProxyFactoryFactory("NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle"); var fluentConfiguration = Fluently.Configure() .Database(configuration) .Mappings(m => { m.AutoMappings.Add(new AutoPersistenceModelGenerator().Generate()); m.FluentMappings.AddFromAssemblyOf(); m.HbmMappings.AddFromAssemblyOf (); }); var nhConfiguration = fluentConfiguration.BuildConfiguration(); var validationEngine = new ValidatorEngine(); validationEngine.Configure(); ValidatorInitializer.Initialize(nhConfiguration, validationEngine); var sessionFactory = nhConfiguration.BuildSessionFactory(); NHibernateSession.SessionFactories.Add( webSessionStorage.FactoryKey, sessionFactory); NHibernateSession.Storages.Add(webSessionStorage.FactoryKey, webSessionStorage);
I'm hoping we can clean up the NHibernateSession.Init method somewhat because calling it with all those nulls looks mighty sketchy. But since Sharp Architecture recently came out with an official 1.0 version, I'm hesitant to start mucking with public interfaces.
Kyle the Private