Expressions Builder In .NET And EF

In MVC applications using the Entity Framework, we may encounter situations where you have to extract data with your expressions. Let’s share how you can use Expression<Func<T, bool>> with MVC and Entity Framework. Using Expression we can create dynamic filters and apply them individually or all at once on the database dataset.

Here I have created a dynamic static class to build expressions that allow us to dynamically create complex predicates in LINQ expressions,

 public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> True<T>() { return f => true; }
        public static Expression<Func<T, bool>> False<T>() { return f => false; }

        public static Expression<Func<T, bool>> CombineFilters<T>(List<Expression<Func<T, bool>>> filters)
        {
            var combinedFilter = True<T>();

            foreach (var filter in filters)
            {
                combinedFilter = combinedFilter.And(filter);
            }

            return combinedFilter;
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
            return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, expr2.Body.ReplaceParameter(expr2.Parameters[0], expr1.Parameters[0])), expr1.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
            return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, expr2.Body.ReplaceParameter(expr2.Parameters[0], expr1.Parameters[0])), expr1.Parameters);
        }

        private static Expression ReplaceParameter(this Expression expression, ParameterExpression source, ParameterExpression target)
        {
            return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
        }

        private class ParameterReplacer : ExpressionVisitor
        {
            public ParameterExpression Source;
            public ParameterExpression Target;

            protected override Expression VisitParameter(ParameterExpression node)
            {
                return node == Source ? Target : base.VisitParameter(node);
            }
        }
    }

This tutorial presents methods for true and false expressions, combining filters using AND and OR arguments and substituting parameters in expressions, which are useful in parameterized expressions will be combined in expression.

Here is an example of using these methods.

 private List<MyTable> DisplayReport(FilterVM model, string search)
{
     var data = new List<MyTable>();
     var filterExpressions = new List<Expression<Func<MyTable, bool>>>();

     filterExpressions.Add(p => p.BrandID == "ABC");

 if (!string.IsNullOrWhiteSpace(search))
            {
                filterExpressions.Add(p => p.Name == search);
            }
 var combinedFilter = PredicateBuilder.CombineFilters(filterExpressions);
 return _db.MyTables.Where(combinedFilter).ToList();

}

I hope you found this tutorial easy to follow and understand.