Search code examples
c#linqnhibernateexpression-trees

Expression Trees in NHibernate


I have a method which have this signature

public static IList<T> GetBy<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression)

I use to pass lambda expressions and make search restriction in nhibernate by retrieving data from expressiontree.

So when class user pass something like :

c => c.fullName == "John" && c.lastName == "Smith" && c.lastName != "" || c.fullName != ""  && c.Age > 18

I get to read this structure from expression tree, that way I have a full intellisense way to provide searching criteria

In other words: I need to pass searching criteria to data access layer (Nhibernate)

So I need to extract criteria from expression tree and then pass it to n hibernate by example :

c=>c.fullname = "John" 

I will extract the following information from the expression tree :

propertyname = fullname , value = "John" , restrictiontype = "equality" 

and then pass this info to nhibernate as following :

ICriteria crit = session.CreateCriteria(typeof(T));
                    crit.Add(Restrictions.Eq(propretyName, value));
    IList<T> list = crit.Add(List<T>())
                    return list;

Any way the problem is it's really hard to read from expressiontree, so I was wondering if you guys have any easy way of maybe iterating inside expressiontree to pull data, or maybe you guys have some code to retrieve data from ExpressionTree.


Solution

  • Here is some code that retrieves the information you mentioned. I’m sure you can extend this to include additional information you might be looking for.

    public class Criterion
    {
        public string PropertyName;
        public object Value;
        public ExpressionType RestrictionType;
    }
    
    [....]
    
    public static IEnumerable<Criterion> GetCriteria<T>(Expression<Func<T, bool>> expression)
    {
        return getCriteria<T>(expression.Body);
    }
    private static IEnumerable<Criterion> getCriteria<T>(Expression expression)
    {
        if (expression is BinaryExpression)
        {
            var bin = (BinaryExpression) expression;
            if (bin.NodeType == ExpressionType.And || bin.NodeType == ExpressionType.AndAlso ||
                bin.NodeType == ExpressionType.Or || bin.NodeType == ExpressionType.OrElse)
                return getCriteria<T>(bin.Left).Concat(getCriteria<T>(bin.Right));
    
            if (bin.Left is MemberExpression)
            {
                var me = (MemberExpression) bin.Left;
                if (!(bin.Right is ConstantExpression))
                    throw new InvalidOperationException("Constant expected in criterion: " + bin.ToString());
                return new[] { new Criterion {
                    PropertyName = me.Member.Name,
                    Value = ((ConstantExpression) bin.Right).Value,
                    RestrictionType = bin.NodeType
                } };
            }
    
            throw new InvalidOperationException("Unsupported binary operator: " + bin.NodeType);
        }
    
        throw new InvalidOperationException("Unsupported expression type: " + expression.GetType().Name);
    }