Search code examples
c#nhibernatequeryovernhibernate-criteria

Dynamic conjunction building for Nhibernate QueryOver in c#


Im trying to build somewhat of filter builder for my collections.

public static NHibernate.Criterion.Conjunction CreateConjunction<T>(this IEnumerable<FilterDescriptor> _filters)
        {
            NHibernate.Criterion.Conjunction conjunction = new NHibernate.Criterion.Conjunction();

            foreach (var filter in _filters)
            {
                PropertyInfo propertyInfoObj = typeof(T).GetProperty(filter.Member);
                conjunction.Add<T>(x => propertyInfoObj.GetValue(x, null) == filter.Value);
            }

            return conjunction;
        }

I can said of course when invoking line conjunction.Add throws an error 'variable 'x' of type 'Foo' referenced from scope '', but it is not defined nhibernate queryOver'.

How can I build conjunction or expression that can be accepted by queryOver.Where() ?

I'm looking for rather universal solution for adding filtering to my QueryOvers, any suggestion ?


Solution

  • I did walk around using criterion ald building simple expressions, all looks like that:

    public static void AddFilterCriteria<T>(this NHibernate.IQueryOver<T,T> _this, IEnumerable<Filter> _filters)
    {
        foreach (var filter in _filters)
        {
            _this.And(GetCriterion(filter));
        }
    }
    
    public static NHibernate.Criterion.ICriterion GetCriterion(Filter _filter)
    {
        if (_filter.Value is string)
        {
            return GetCriterionForString(_filter);
        }
    
        switch (_filter.Operator)
        {
            case eFilterOperator.IsEqualTo:
                {
                    return NHibernate.Criterion.Expression.Eq(_filter.Member, _filter.Value);
                }
            case eFilterOperator.IsNotEqualTo:
                {
                    return NHibernate.Criterion.Expression.Not(NHibernate.Criterion.Expression.Eq(_filter.Member, _filter.Value));
                }
            case eFilterOperator.IsGreaterThan:
                {
                    return NHibernate.Criterion.Expression.Gt(_filter.Member, _filter.Value);
                }
            case eFilterOperator.IsGreaterThanOrEqualTo:
                {
                    return NHibernate.Criterion.Expression.Ge(_filter.Member, _filter.Value);
                }
            case eFilterOperator.IsLessThan:
                {
                    return NHibernate.Criterion.Expression.Lt(_filter.Member, _filter.Value);
                }
            case eFilterOperator.IsLessThanOrEqualTo:
                {
                    return NHibernate.Criterion.Expression.Le(_filter.Member, _filter.Value);
                }
            default:
                throw new InvalidOperationException();
        }
    }
    

    There is some special logic for string criteria building, but its analogic and pretty simple as rest of it. You can build conjunctions, disjunctions and return them as ICriteria like that for example:

    case eFilterOperator.Contains:
                        {
                            NHibernate.Criterion.Conjunction conjunction = new NHibernate.Criterion.Conjunction();
                            conjunction.Add(NHibernate.Criterion.Expression.IsNotNull(_filter.Member)); 
                            conjunction.Add(NHibernate.Criterion.Expression.InsensitiveLike(_filter.Member, _filter.Value.ToString(), NHibernate.Criterion.MatchMode.Anywhere));
                            return conjunction;
                        }
    

    Everything works fine and I dont need to read whole data from database before applying filters, what was my goal.

    PS Filter.Member is string Filter.Value is object and operator is enum