I've been doing quite a bit of messing around with Rhino Commons the last few days. I really like the ability it has to let you use Castle ActiveRecord without needing to derive from a base class, to provide access to objects through the Repository<T> class, and to not have to use NHibernate XML configuration files (yuk).
However, one of my struggles with it is that the library assumes that you are in a web app, as you must derive your application class from the UnitOfWorkApplication class, which is itself derived from HttpModule. Well, this is a problem if you are writing a console app, service, or other non-web application, as the UnitOfWorkApllication class does a lot of setup in its constructor that is needed to use all of the cool features of the library.
So, after much diving into the source code to figure out what's going on (there is almost no documentation on how this library actually works), I was able to write my own application class, appropriately called GenericUnitOfWorkApplication, which can be used in non-web apps (specifically, console apps).
As an example, here is my sample console application which show you how to use this class, while storing a new domain object in the database and then iterating across all of them:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Model;
using Rhino.Commons;
using _42Spikes.Rhino.Commons;
namespace TestConsole
{
class Program : GenericUnitOfWorkApplication
{
static void Main(string[] args)
{
new Program().run();
}
private void run()
{
UnitOfWork.Start();
Repository<User>.Save(new User("Mike Heydt"));
With.Each<User>(
Repository<User>.FindAll(),
t => Console.WriteLine(t.Name));
UnitOfWork.Current.Dispose();
}
}
public abstract class With
{
public delegate void operationdelegate<T>(T o);
public static void Each<T>(
IEnumerable<T> objects,
operationdelegate<T> f)
{
foreach (T i in objects) f(i);
}
}
}
You can download this entire solution (short of the database)
here.
What's going on there is that the Program class derives from my GenericUnitOfWorkApplication class, and when its constructor is run it does all the initialization of the Castle and NHibernate stuff that the UnitOfWorkApplication class does, minus all of the web stuff (like setting up things to manage unit of work mapping to ASP.NET sessions).
The down side of this is that the unit of work is not set up automaticaly, and you need to do it yourself. Oh well, a small price to pay I think for this great functionality.
And I really like the brevity of this code and now much functionality it has in just a few lines. Also note my use of a custom With class to apply a lambda function to each element of the database, which I think is quite nice syntax.
Just thinking out loud here, I still think that there are a few things things that I still need to do with this code:
- I like that the original UnitOfWorkApplication would map units of work to the session automaticaly. It's only a few lines of code up there, but it would be nice if this could somehow be automatic. I think the solution to this is to use PostSharp to apply an aspect to specific methods that automatically create the UnitOfWork. That would be cool.
- This class is still a problem in an application like WPF where your app object needs to derive from a framework class, so this class is not really of use in that situation. However, there is nothing magic about this class as it does not have to be your base class, you can create a singleton instance of it in your app. All that is needed is the initialization code run in the constructor.
Which leads me to wonder about the use of AoP. It would seem to me that you should be able to automatically inject this functionality into your application class. I'll have to look into how to do that with PostSharp.