Friday 27 April 2012

Using filters for unmapped columns in NHibernate

Using filters in NHibernate is a little known feature to new users. Filters can be applied in quite few places.

This blog shows us how we can apply a filter onto the class definition:-
<class name="Domain.Model.BlogPost, Domain.Model" table="Posts" 
       where="(IsLive=1)">
    ...
</class>
However be warned this will always return blog posts that are live. Sometimes you may want to get blog posts that are not live. If you use a filter this way then you will never be able to return isLive=0 or ALL blogs regardless of the flag.

Fortunately NHibernate allows us to switch filters on/off at a flick of a switch, add this to your mappings file:-
<filter-def name="BlogFlag">
    <filter-param name=":isLive" type="System.Int"/>
</filter-def>

<class name="Domain.Model.BlogPost, Domain.Model" table="Posts">
  <filter name="BlogFlag" condition="(isLive=:flag)"/>
    ...
</class>
Using the flag could not be simpler, just set the flag before you query:-
//return live blogs
session.EnableFilter("BlogFlag").SetParameter("isLive", 1);
session.QueryOver<MyEntity>();

//return blogs that are not live
session.EnableFilter("BlogFlag").SetParameter("isLive", 0);
session.QueryOver<MyEntity>();

//return all blogs
session.QueryOver&t;MyEntity>();
Now one question you are asking is why would I use filters? Why wouldn't I just use
//Use a where clause! Isn't this more sensible?
session.QueryOver<MyEntity>()
  .Where(w => w.IsLive == isLive);
However one of the unknown undocumented features of filters is that the database column IsLive, DOES not need to mapped to a fully mapped property.

The second reason is that if I ALWAYS want just live Blog posts therefore adding where="(IsLive=1)"> to the class definition makes sense as the developer will does not need to remember to add the where clause for EVERY query.

In the next blog post I will show you how to use filters on collections.

No comments:

Post a Comment