My biggest problem with NHibernate at the moment is the way its Sessions work. Not that they work any worse than Connections used to work in ADO.NET but with all NHibernate magic in place it is natural to expect that the Sessions can also be managed in some magical way :)
Consider, for example, the following code:
var file = Db.Retrieve<File>(message.FileId);
string outputFile = Path.Combine(OutputPath, file.BaseName);
My Db.Retrieve uses Spring's NHibernate Template to open a Session, do Session.Load(fileId), and close Session. As Ayende explains in this post, Load returns a proxy object. The problem with this of course, is having no session open to get file.BaseName in the next line.
Possible solutions:
- Stop using Spring's NHibernate Template and just use SessionFactory and Session Directly. This seems to be in line with the approach that Ayende advocates here.
- Do as Spring's manual recommends, i.e. enable declarative transaction management. This way the entire method will be decorated with [Transaction] attribute and that will instruct Spring to keep the Session open for the entire duration of the method. My problem with this is a lot of feedling with configs required to get the declarative transactions to work. Last time I tried it I could not get it to work and I don't seem to have time right now.
- A variant of number two but with explicit transaction management. This is much easier to implement and this is what I do in my current project, but it is far from elegant as the code ends up looking like this:
private string GetBaseName(CommandMessage message)
{
var tran = Db.BeginTransaction();
try
{
var file = Db.Retrieve<File>(message.FileId);
string outputFile = Path.Combine(OutputPath, file.BaseName);
Db.Commit(tran);
return outputFile;
}
catch (Exception)
{
Db.Rollback(tran);
throw;
}
}
I think, as more and more code gets this ugly, I'll reconsider and go to Option 2. Ayende's minimalistic approach seems too Zenish for my overcomplicated mind, at least for now :).
Tags: