The object-relational mapper for .NET

Typesafe ICriteria using Lambda Expressions

Originally announced on my own blog here: Using Lambda Expressions with NHibernate


I love NHibernate, but I've never been a fan of the 'magic strings' used in the ICriteria API. Now we have .Net 3.5, and the ability to have strongly-typed queries built into the language, and a corresponding NH-Contrib project (NHibernate.Linq) to allow us to use LINQ with NHibernate.

However, there are still times when you need to use the ICriteria API (or HQL) to achieve the results you want.

When ICriteria is more powerful than LINQ

Consider the following query:

    session.CreateCriteria(typeof(Person), "personAlias")

        .SetFetchMode("personAlias.PersonDetail", FetchMode.Eager)
        // to prevent select n+1
        .SetLockMode("personAlias", LockMode.Upgrade)
        // to read-lock the data until commit

        .Add(Expression.Like("Name", "%anna%"))
        // includes the name 'Polyanna', 'Annabella', ...

LINQ provides a high-level abstraction of a query that can potentially be run against any datasource. However, this abstraction comes at a cost (try writing the above query in LINQ). LINQ (out of the box) has no concept of:

  • Fetch modes (an ORM concept);
  • Locking (a database/transaction concept);
  • SQL specific functions (there is not always an equivalent C# function).

So ICriteria and HQL will not be obsolete - they will quite happily live side-by-side with LINQ.

Typesafe Syntax for ICriteria

In order to implement LINQ, .Net 3.5 also introduced both Extension Methods and Lambda Expressions

Extension methods allow us to extend the ICriteria interface with our own methods, while Lambda Expressions allow us to create typesafe expressions that can be examined at runtime. So with some extra syntactic sugar, the above query can be written as:

    Person personAlias = null;
    session.CreateCriteria(typeof(Person), () => personAlias)

        .SetFetchMode(() => personAlias.PersonDetail, FetchMode.Eager)

        .SetLockMode(() => personAlias, LockMode.Upgrade)

        .Add(SqlExpression.Like<Person>(p => p.Name, "%anna%"))

The 'magic strings' are gone! This code uses a combination of Extension Methods and Lambda Expressions to create a typesafe version of the ICriteria. We can now also use our refactoring tools to rename, or find references to properties safe if the knowledge that the IDE will pick them up.

The extensions methods required to do this have been packaged up into a project (link below), making it easy to add this to your own .Net 3.5 NHibernate project.

With the addition of projects like Fluent NHibernate , perhaps 'magic strings' will finally become a thing of the past.

Some links:

Posted Wed, 07 January 2009 12:08:00 AM by FlukeFan
Filed under:

comments powered by Disqus
© NHibernate Community 2024