Okay, it looks like I can track down fairly easily what books I read, when I read Working Effectively with Legacy Code, I wrote Rhino Mocks. Now I am reading Applying Domain-Driven Design and Patterns, and I wrote the NHibernate Query Generator.
So, what is this all about?
NHibernate has two major API for querying objects. The first one is called the query API, and uses HQL, a language similar to SQL but with OOP aspirations. The second is called the criteria API, and it is far simpler API, but it is also much easier to use.
Here is a simple example of using the criteria API using my Repository sample from yesterday:
ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(Expression.Eq("City", "London"));
Now, those of you that already knows me know that I have a passionate dislike to strings. I wrote a mock objects library because of this issue, so I may need physcological therapy in the future, but I hate strings.
Well, what do I do when there is something that I don't like? I fix it.
In this case, there where two main options, run time proxying and code generation.
Run time proxying is similar to what I do in Rhino Mocks, and it may look like this:
ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(Expression.Eq(Expr.Of<Customer>().Name,"London"));
This has the disadvantages of being both ugly and complex, so I turned to the other route. I build a small application which takes an NHibernate mapping file (hbm.xml) file, and output a strongly typed query wrapper. The above query can now be used like this:
ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(
Where.Customer.City.Eq("London") );
This is much better, and of course that you get all the other nice things about the expression API (like Between, In, etc).
You can get it here, binaries only. Source would have to wait for a while, my subversion provider has run out of room. Note that the code it generates relies on a class called NamedExpression. The class is included in the binary, so just add it to your project and you are done.
I also added support for queries, since I didn't want to leave the other side of the API high and dry, it means that you can do this:
ICollection<Customer> customersInLondon = Repository<Customer>.FindAll(
Queries.AllCustomersInCity, new Parameter("city", "London"));
Here is a little FAQ