0
votes

I am trying to create a dynamic search expression tree that takes a list of table columns and an array of search terms and returns a expression. The code below works fine with non-value types but I can not figure out how to make it work with ValueType properties. i.e. strings work but numbers do not.

    public static Expression<Func<T, bool>> CreateDynamicSearch<T>(List<string> searchableColumns, string[] searchTerms)
    {
        var predicate = PredicateBuilder.New<T>(true);
        try {
            foreach (var term in searchTerms) {
                var colPredicate = PredicateBuilder.New<T>(true);
                foreach (var columnName in searchableColumns) {
                    var columnFilter = PredicateBuilder.New<T>(false);
                    var param = Expression.Parameter(typeof(T), "a");
                    MemberExpression prop = Expression.Property(param, columnName);
                    var propInfo = (PropertyInfo)prop.Member;
                    MethodCallExpression call;
                    if (propInfo.PropertyType.IsValueType) {
                        if (int.TryParse(term, out int num)) {
                            call = Expression.Call(prop, "Equals", new Type[0],Expression.Constant(num)); 
                            columnFilter = columnFilter.And(Expression.Lambda<Func<T, bool>>(call, param));
                            colPredicate = colPredicate.Or(columnFilter);
                        }
                    }
                    else {
                        call = Expression.Call(prop, "Contains", new Type[0], Expression.Constant(term));
                        columnFilter = columnFilter.And(Expression.Lambda<Func<T, bool>>(call, param));
                        colPredicate = colPredicate.Or(columnFilter);
                    }
                }
                //AND the term predicate with the previous predicate
                predicate = predicate.And(colPredicate);
            }
        }
        catch (Exception ex) {
            throw;
        }
        return predicate;
    }

I am just delving into expressions trees so any suggestions would be appreciated.

Using this code I currently get and error when I get to the ValueType. The error is

No method 'Equals' on type 'System.Nullable`1[System.Int32]' is compatible with the supplied arguments.

1
What happens when you try to handle an Int? - NetMage
I get the error message that I added above. - John S
Ok it seems that it has something to do with the fact that the DB field is a nullable int (not my call). If the DB was a true int the Equals would work just fine. - John S
Did you try my suggest change with Convert? - NetMage
Convert did not work in this case because the num variable type was a nullable int. - John S

1 Answers

-1
votes

Using LINQPad and analyzing a lambda, it seems the compiler converts the Int32 constant to Object and calls the Object Equals(object) version:

Expression.Call(prop, "Equals", new Type[0], Expression.Convert(Expression.Constant(num), typeof(Object)));