Search code examples
.netnhibernatenhibernate-criteria

Create Custom Criterion in NHibernate?


I'm still a bit of a n00b when it comes to NHibernate. Let's say I have the following:

var myCriteria = this.Session.CreateCriteria(typeof(SomeModel))
                         .Add(Restrictions.Eq("SomeProperty", someValue);

Then, let's say I want to add criteria in a way that's reusable. Meaning, I want to make a custom criterion. I'm seeing very, very little information online on this. Specifically, I'd like to turn the following:

var myCriteria = this.Session.CreateCriteria(typeof(SomeModel))
                .Add(Restrictions.Eq("SomeProperty", someValue)
                .CreateAlias("SomeClass", "alias", JoinType.LeftOuterJoin)
                .Add(Restrictions.Eq("alias.SomeOtherProperty", someOtherValue));

Into the following:

var myCriteria = this.Session.CreateCriteria(typeof(SomeModel))
                             .Add(Restrictions.Eq("SomeProperty", someValue)
                             .Add(this.GetAliasCriterion());

Thus extracting

      .CreateAlias("SomeClass", "alias", JoinType.LeftOuterJoin)
             .Add(Restrictions.Eq("alias.SomeOtherProperty", someOtherValue)); 

into a method.

Is this possible? How does this work?


Solution

  • Personally, I prefer using Linq to NHibernate instead of criteria. It is already included in the latest release of NHibernate, just add "using NHibernate.Linq" to your cs file, as all of the L2H methods are extension methods.

    If I want to make a predicate/criteria reusable with L2H, it'll look something like this:

    public partial class Person 
    {
        //yes, this is kind of ugly, but if I have a complicated predicate that 
        //I want to reuse, I'll make a static method on the entity itself.
        public static Expression<Func<Person, bool>> HasPrimaryRole(string roleCode)
        {
            return p => p.Roles.Any(r => r.RoleCode == roleCode && r.IsPrimary);
        }
    }
    

    Usage looks like this:

    var session = GetSession();
    var midwestSalesManagers = session.Query<Person>()
        .Where(p => p.Region == "Midwest").Where(Person.HasPrimaryRole("RSM"));
    

    or alternatively you could do this:

    var midwestSalesManagers = session.Query<Person>()
        .Where(Expression.And(p => p.Region == "Midwest", Person.HasPrimaryRole("RSM")));
    

    I haven't fully tested all of this, but I hope you get my drift. I think it is pretty readable and avoids usage of magic strings so it is refactor friendly.