NHibernate Forge
The official new home for the NHibernate for .NET community

Typesafe ICriteria using Lambda Expressions

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

Introduction

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 ene 07 2009, 10:08 a.m. by Richard Brown

Comments

bunceg wrote re: Typesafe ICriteria using Lambda Expressions
on 01-12-2009 13:49

Nice idea, thanks!

Stefan Steinegger wrote re: Typesafe ICriteria using Lambda Expressions
on 01-27-2009 9:31

Looks great. But how can you find out which property is meant by the lamda expression? I thought that it is not possible to "see" the content of an expression, that you only can execute it. (This would return the value of the property, not its name or PropertyInfo)

By the way, the Documentation link is broken somehow. It tries to download it. (Same on your project page.)

Richard Brown wrote re: Typesafe ICriteria using Lambda Expressions
on 01-27-2009 9:42

ssteinegger,

LambdaExpressions are not evaluated until runtime, so you are able to retrieve the PropertyInfo at runtime too.

The docs are hosted from the Google Project downloads sections - Google adds a host-header that makes IE prompt for download, but you should still just be able to 'open' it (it's just a regular HTML page).

Stefan Steinegger wrote re: Typesafe ICriteria using Lambda Expressions
on 02-09-2009 16:21

This is pretty cool. I have to try it for my mapping tester configuration, where I use property names in strings.

Docs: I'm using Firefox. I can choose Firefox as the application to open the file, but then I see the HTML tags.

Richard Brown wrote re: Typesafe ICriteria using Lambda Expressions
on 02-09-2009 19:38

Ah, sorry, I can't control how the Google downloads return the headers.

I tried it in Firefox, and if you save it to disk you're fine.

Also the docs are in the .zip download too; the separate download is just for convenience.

Powered by Community Server (Commercial Edition), by Telligent Systems