none
PredicateBuilder fails on nested predicates with LINQ to Entities

    Question

  • I'm using Joe Albahari's great PredicateBuilder ,
    but although it works great with chaining predicates together, it fails if I add a nested predicate.
    Here's what I'm trying to do:

                   var predicate = PredicateBuilder.True<Report>();
                   bool isFiltered = false;

                   if ((titlePattern != null) && (titlePattern.Length > 0))
                   {
                       predicate = predicate.And(f => f.Title.Contains(titlePattern));
                   }

                   if ((keywords != null) && (keywords.Length > 0))
                   {
                       predicate = predicate.And(Report.SummaryContains(keywords));
                    }

                    // Compile the predicate.
                    Func<Report, bool> query = predicate.Compile();

                    // Get all of the reports in the model that match the provided search terms.
                    ObjectQuery<Report> reports = _db.ReportSet;
                    return reports.AsExpandable().Where(predicate);


    And here's the generic method that checks the Summary column for any of the keywords.

            // Get an expression to determine if the Summary property contains any of the provided keywords
            public static Expression<Func<Report, bool>> SummaryContains(params string[] keywords)
            {
                Expression<Func<Report, bool>> predicate = PredicateBuilder.False<Report>();

                foreach (string keyword in keywords)
                {
                    string temp = keyword;
                    predicate = predicate.Or(f => f.Summary.Contains(temp));
                }

                return predicate;

            }

    It looks like this is suggested on Joe Albahari's page, but whenever I add the complexity like the SummaryContains method, I get the error message "The parameter 'f' was not bound in the specified LINQ to Entities query expression.".

    Any ideas what I'm doing wrong? Or is it yet another thing that doesn't work with LINQ and the Entity Framework?

    Thanks,

    Tim
    • Edited by TJ Rourke Tuesday, June 09, 2009 11:33 PM
    Tuesday, June 09, 2009 10:48 PM

All replies

  • The answer seems to be that PredicateBuilder doesn't handle this. However, I saw another question answered by Peter Qian and referencing Colin Meek's blog .

    Colin says in his post (paraphrasing here) that LINQ to Entities is confused and doesn't see the 'f' parameter from one level of predicates as being the same 'f' parameter in the nested levels. Or at least, that's how it seems to me. He didn't really specify my case. But I tried it and PredicateBuilder worked with the complex query.

    Whee! Time to go home!

    Oh, and for anyone else who runs into this, here's what worked for me.

    1. Implement the ExpressionVisitor class found at the bottom of a referenced post on Matt Warren's blog (also a good reference for building IQueryable providers, BTW).

    NOTE: This class will require references in your source code file:
       
        using System.Collections.ObjectModel;
        using System.Linq.Expressions;

    2. Implement Colins' ParameterRebinder and Utility classes from his post at URL http://blogs.msdn.com/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx.

    NOTE: These two classes will require this reference in your source code file:
       
        using System.Linq.Expressions;

    3. In your own classes where you have a line like this:

                 var predicate = PredicateBuilder.True<Report>();
                 if ((titlePattern != null) && (titlePattern.Length > 0))
                {
                    predicate = predicate.And(f => f.Title.Contains(titlePattern));
                    isFiltered = true;
                }

    change the "predicate = predicate." bit with "predicate = Utility.", to use the visitor:

               predicate = Utility.And(predicate, Report.TitleContains(titlePattern));


    Many thanks to Colin, Matt, Joe, Webbert (who asked the question) and Peter Qian (who answered Webbert's question).
    Tuesday, June 09, 2009 11:22 PM
  • My hero! =O)

    You just saved me alot of time figuring this out!
    Tried it, and it worked...

    The way you put all the pieces together was perfect but linking everything to blogs and pages around the web might break in the future so I'll try to add all the code in one piece here. The links to the stuff below can be found in the previous post.
    Many thanks to all of you who made the effort!

    Add the following classes in your project:
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Linq.Expressions;
    
    namespace YourNamespaceHere
    {
    
        public static class Utility
        {
            public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
            {
                // build parameter map (from parameters of second to parameters of first)
                var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
    
                // replace parameters in the second lambda expression with parameters from the first
                var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
    
                // apply composition of lambda expression bodies to parameters from the first expression 
                return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
            }
    
            public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
            {
                return first.Compose(second, Expression.And);
            }
    
            public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
            {
                return first.Compose(second, Expression.Or);
            }
        }
    
        public class ParameterRebinder : ExpressionVisitor
        {
            private readonly Dictionary<ParameterExpression, ParameterExpression> map;
    
            public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }
    
            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }
    
            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;
                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }
                return base.VisitParameter(p);
            }
        }
    
    
        public abstract class ExpressionVisitor
        {
            protected ExpressionVisitor()
            {
            }
    
            protected virtual Expression Visit(Expression exp)
            {
                if (exp == null)
                    return exp;
                switch (exp.NodeType)
                {
                    case ExpressionType.Negate:
                    case ExpressionType.NegateChecked:
                    case ExpressionType.Not:
                    case ExpressionType.Convert:
                    case ExpressionType.ConvertChecked:
                    case ExpressionType.ArrayLength:
                    case ExpressionType.Quote:
                    case ExpressionType.TypeAs:
                        return this.VisitUnary((UnaryExpression)exp);
                    case ExpressionType.Add:
                    case ExpressionType.AddChecked:
                    case ExpressionType.Subtract:
                    case ExpressionType.SubtractChecked:
                    case ExpressionType.Multiply:
                    case ExpressionType.MultiplyChecked:
                    case ExpressionType.Divide:
                    case ExpressionType.Modulo:
                    case ExpressionType.And:
                    case ExpressionType.AndAlso:
                    case ExpressionType.Or:
                    case ExpressionType.OrElse:
                    case ExpressionType.LessThan:
                    case ExpressionType.LessThanOrEqual:
                    case ExpressionType.GreaterThan:
                    case ExpressionType.GreaterThanOrEqual:
                    case ExpressionType.Equal:
                    case ExpressionType.NotEqual:
                    case ExpressionType.Coalesce:
                    case ExpressionType.ArrayIndex:
                    case ExpressionType.RightShift:
                    case ExpressionType.LeftShift:
                    case ExpressionType.ExclusiveOr:
                        return this.VisitBinary((BinaryExpression)exp);
                    case ExpressionType.TypeIs:
                        return this.VisitTypeIs((TypeBinaryExpression)exp);
                    case ExpressionType.Conditional:
                        return this.VisitConditional((ConditionalExpression)exp);
                    case ExpressionType.Constant:
                        return this.VisitConstant((ConstantExpression)exp);
                    case ExpressionType.Parameter:
                        return this.VisitParameter((ParameterExpression)exp);
                    case ExpressionType.MemberAccess:
                        return this.VisitMemberAccess((MemberExpression)exp);
                    case ExpressionType.Call:
                        return this.VisitMethodCall((MethodCallExpression)exp);
                    case ExpressionType.Lambda:
                        return this.VisitLambda((LambdaExpression)exp);
                    case ExpressionType.New:
                        return this.VisitNew((NewExpression)exp);
                    case ExpressionType.NewArrayInit:
                    case ExpressionType.NewArrayBounds:
                        return this.VisitNewArray((NewArrayExpression)exp);
                    case ExpressionType.Invoke:
                        return this.VisitInvocation((InvocationExpression)exp);
                    case ExpressionType.MemberInit:
                        return this.VisitMemberInit((MemberInitExpression)exp);
                    case ExpressionType.ListInit:
                        return this.VisitListInit((ListInitExpression)exp);
                    default:
                        throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType));
                }
            }
    
            protected virtual MemberBinding VisitBinding(MemberBinding binding)
            {
                switch (binding.BindingType)
                {
                    case MemberBindingType.Assignment:
                        return this.VisitMemberAssignment((MemberAssignment)binding);
                    case MemberBindingType.MemberBinding:
                        return this.VisitMemberMemberBinding((MemberMemberBinding)binding);
                    case MemberBindingType.ListBinding:
                        return this.VisitMemberListBinding((MemberListBinding)binding);
                    default:
                        throw new Exception(string.Format("Unhandled binding type '{0}'", binding.BindingType));
                }
            }
    
            protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
            {
                ReadOnlyCollection<Expression> arguments = this.VisitExpressionList(initializer.Arguments);
                if (arguments != initializer.Arguments)
                {
                    return Expression.ElementInit(initializer.AddMethod, arguments);
                }
                return initializer;
            }
    
            protected virtual Expression VisitUnary(UnaryExpression u)
            {
                Expression operand = this.Visit(u.Operand);
                if (operand != u.Operand)
                {
                    return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method);
                }
                return u;
            }
    
            protected virtual Expression VisitBinary(BinaryExpression b)
            {
                Expression left = this.Visit(b.Left);
                Expression right = this.Visit(b.Right);
                Expression conversion = this.Visit(b.Conversion);
                if (left != b.Left || right != b.Right || conversion != b.Conversion)
                {
                    if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null)
                        return Expression.Coalesce(left, right, conversion as LambdaExpression);
                    else
                        return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method);
                }
                return b;
            }
    
            protected virtual Expression VisitTypeIs(TypeBinaryExpression b)
            {
                Expression expr = this.Visit(b.Expression);
                if (expr != b.Expression)
                {
                    return Expression.TypeIs(expr, b.TypeOperand);
                }
                return b;
            }
    
            protected virtual Expression VisitConstant(ConstantExpression c)
            {
                return c;
            }
    
            protected virtual Expression VisitConditional(ConditionalExpression c)
            {
                Expression test = this.Visit(c.Test);
                Expression ifTrue = this.Visit(c.IfTrue);
                Expression ifFalse = this.Visit(c.IfFalse);
                if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse)
                {
                    return Expression.Condition(test, ifTrue, ifFalse);
                }
                return c;
            }
    
            protected virtual Expression VisitParameter(ParameterExpression p)
            {
                return p;
            }
    
            protected virtual Expression VisitMemberAccess(MemberExpression m)
            {
                Expression exp = this.Visit(m.Expression);
                if (exp != m.Expression)
                {
                    return Expression.MakeMemberAccess(exp, m.Member);
                }
                return m;
            }
    
            protected virtual Expression VisitMethodCall(MethodCallExpression m)
            {
                Expression obj = this.Visit(m.Object);
                IEnumerable<Expression> args = this.VisitExpressionList(m.Arguments);
                if (obj != m.Object || args != m.Arguments)
                {
                    return Expression.Call(obj, m.Method, args);
                }
                return m;
            }
    
            protected virtual ReadOnlyCollection<Expression> VisitExpressionList(ReadOnlyCollection<Expression> original)
            {
                List<Expression> list = null;
                for (int i = 0, n = original.Count; i < n; i++)
                {
                    Expression p = this.Visit(original[i]);
                    if (list != null)
                    {
                        list.Add(p);
                    }
                    else if (p != original[i])
                    {
                        list = new List<Expression>(n);
                        for (int j = 0; j < i; j++)
                        {
                            list.Add(original[j]);
                        }
                        list.Add(p);
                    }
                }
                if (list != null)
                {
                    return list.AsReadOnly();
                }
                return original;
            }
    
            protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment)
            {
                Expression e = this.Visit(assignment.Expression);
                if (e != assignment.Expression)
                {
                    return Expression.Bind(assignment.Member, e);
                }
                return assignment;
            }
    
            protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding)
            {
                IEnumerable<MemberBinding> bindings = this.VisitBindingList(binding.Bindings);
                if (bindings != binding.Bindings)
                {
                    return Expression.MemberBind(binding.Member, bindings);
                }
                return binding;
            }
    
            protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding)
            {
                IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(binding.Initializers);
                if (initializers != binding.Initializers)
                {
                    return Expression.ListBind(binding.Member, initializers);
                }
                return binding;
            }
    
            protected virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original)
            {
                List<MemberBinding> list = null;
                for (int i = 0, n = original.Count; i < n; i++)
                {
                    MemberBinding b = this.VisitBinding(original[i]);
                    if (list != null)
                    {
                        list.Add(b);
                    }
                    else if (b != original[i])
                    {
                        list = new List<MemberBinding>(n);
                        for (int j = 0; j < i; j++)
                        {
                            list.Add(original[j]);
                        }
                        list.Add(b);
                    }
                }
                if (list != null)
                    return list;
                return original;
            }
    
            protected virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original)
            {
                List<ElementInit> list = null;
                for (int i = 0, n = original.Count; i < n; i++)
                {
                    ElementInit init = this.VisitElementInitializer(original[i]);
                    if (list != null)
                    {
                        list.Add(init);
                    }
                    else if (init != original[i])
                    {
                        list = new List<ElementInit>(n);
                        for (int j = 0; j < i; j++)
                        {
                            list.Add(original[j]);
                        }
                        list.Add(init);
                    }
                }
                if (list != null)
                    return list;
                return original;
            }
    
            protected virtual Expression VisitLambda(LambdaExpression lambda)
            {
                Expression body = this.Visit(lambda.Body);
                if (body != lambda.Body)
                {
                    return Expression.Lambda(lambda.Type, body, lambda.Parameters);
                }
                return lambda;
            }
    
            protected virtual NewExpression VisitNew(NewExpression nex)
            {
                IEnumerable<Expression> args = this.VisitExpressionList(nex.Arguments);
                if (args != nex.Arguments)
                {
                    if (nex.Members != null)
                        return Expression.New(nex.Constructor, args, nex.Members);
                    else
                        return Expression.New(nex.Constructor, args);
                }
                return nex;
            }
    
            protected virtual Expression VisitMemberInit(MemberInitExpression init)
            {
                NewExpression n = this.VisitNew(init.NewExpression);
                IEnumerable<MemberBinding> bindings = this.VisitBindingList(init.Bindings);
                if (n != init.NewExpression || bindings != init.Bindings)
                {
                    return Expression.MemberInit(n, bindings);
                }
                return init;
            }
    
            protected virtual Expression VisitListInit(ListInitExpression init)
            {
                NewExpression n = this.VisitNew(init.NewExpression);
                IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(init.Initializers);
                if (n != init.NewExpression || initializers != init.Initializers)
                {
                    return Expression.ListInit(n, initializers);
                }
                return init;
            }
    
            protected virtual Expression VisitNewArray(NewArrayExpression na)
            {
                IEnumerable<Expression> exprs = this.VisitExpressionList(na.Expressions);
                if (exprs != na.Expressions)
                {
                    if (na.NodeType == ExpressionType.NewArrayInit)
                    {
                        return Expression.NewArrayInit(na.Type.GetElementType(), exprs);
                    }
                    else
                    {
                        return Expression.NewArrayBounds(na.Type.GetElementType(), exprs);
                    }
                }
                return na;
            }
    
            protected virtual Expression VisitInvocation(InvocationExpression iv)
            {
                IEnumerable<Expression> args = this.VisitExpressionList(iv.Arguments);
                Expression expr = this.Visit(iv.Expression);
                if (args != iv.Arguments || expr != iv.Expression)
                {
                    return Expression.Invoke(expr, args);
                }
                return iv;
            }
        }
    }

    And instead of:
    var inner = PredicateBuilder.False<Product>();
    inner = inner.Or (p => p.Description.Contains ("foo"));
    inner = inner.Or (p => p.Description.Contains ("far"));
    
    var outer = PredicateBuilder.True<Product>();
    outer = outer.And (p => p.Price > 100);
    outer = outer.And (p => p.Price < 1000);
    outer = outer.And (inner);
    write:
    var inner = PredicateBuilder.False<Product>();
    inner = YourNamespaceHere.Utility.Or (inner, p => p.Description.Contains ("foo"));
    inner = YourNamespaceHere.Utility.Or (inner, p => p.Description.Contains ("far"));
    
    var outer = PredicateBuilder.True<Product>();
    outer = YourNamespaceHere.Utility.And (outer, p => p.Price > 100);
    outer = YourNamespaceHere.Utility.And (outer, p => p.Price < 1000);
    outer = YourNamespaceHere.Utility.And (outer, inner);

    Kind regards
    Richard

    Wednesday, November 04, 2009 11:46 AM
  • Here's the VB Alternative of Gotham code (btw thanks to you all for this work):

    Imports System
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Linq
    Imports System.Linq.Expressions
    
    Namespace PredicateHelper
    
        Public Module Utility
            'Private Sub New()
            'End Sub
            <System.Runtime.CompilerServices.Extension()> _
                Public Function Compose(Of T)(ByVal first As Expression(Of T), ByVal second As Expression(Of T), ByVal merge As Func(Of Expression, Expression, Expression)) As Expression(Of T)
                ' build parameter map (from parameters of second to parameters of first)
    
                Dim map = first.Parameters.[Select](Function(f, i) New With {f, .s = second.Parameters(i)}).ToDictionary(Function(p) p.s, Function(p) p.f)
    
    
    
                ' replace parameters in the second lambda expression with parameters from the first
                Dim secondBody = ParameterRebinder.ReplaceParameters(map, second.Body)
    
                ' apply composition of lambda expression bodies to parameters from the first expression 
                Return Expression.Lambda(Of T)(merge(first.Body, secondBody), first.Parameters)
            End Function
    
            <System.Runtime.CompilerServices.Extension()> _
                Public Function [And](Of T)(ByVal first As Expression(Of Func(Of T, Boolean)), ByVal second As Expression(Of Func(Of T, Boolean))) As Expression(Of Func(Of T, Boolean))
                Return first.Compose(second, AddressOf Expression.[And])
            End Function
    
            <System.Runtime.CompilerServices.Extension()> _
                Public Function [Or](Of T)(ByVal first As Expression(Of Func(Of T, Boolean)), ByVal second As Expression(Of Func(Of T, Boolean))) As Expression(Of Func(Of T, Boolean))
                Return first.Compose(second, AddressOf Expression.[Or])
            End Function
        End Module
    
        Public Class ParameterRebinder
            Inherits ExpressionVisitor
            Private ReadOnly map As Dictionary(Of ParameterExpression, ParameterExpression)
    
            Public Sub New(ByVal map As Dictionary(Of ParameterExpression, ParameterExpression))
                Me.map = If(map, New Dictionary(Of ParameterExpression, ParameterExpression)())
            End Sub
    
            Public Shared Function ReplaceParameters(ByVal map As Dictionary(Of ParameterExpression, ParameterExpression), ByVal exp As Expression) As Expression
                Return New ParameterRebinder(map).Visit(exp)
            End Function
    
            Protected Overloads Overrides Function VisitParameter(ByVal p As ParameterExpression) As Expression
                Dim replacement As ParameterExpression
                If map.TryGetValue(p, replacement) Then
                    p = replacement
                End If
                Return MyBase.VisitParameter(p)
            End Function
        End Class
    
        Public MustInherit Class ExpressionVisitor
            Protected Sub New()
            End Sub
    
            Protected Overridable Function Visit(ByVal exp As Expression) As Expression
                If exp Is Nothing Then
                    Return exp
                End If
                Select Case exp.NodeType
                    Case ExpressionType.Negate, ExpressionType.NegateChecked, ExpressionType.[Not], ExpressionType.Convert, ExpressionType.ConvertChecked, ExpressionType.ArrayLength, _
                    ExpressionType.Quote, ExpressionType.TypeAs
                        Return Me.VisitUnary(DirectCast(exp, UnaryExpression))
                    Case ExpressionType.Add, ExpressionType.AddChecked, ExpressionType.Subtract, ExpressionType.SubtractChecked, ExpressionType.Multiply, ExpressionType.MultiplyChecked, _
                    ExpressionType.Divide, ExpressionType.Modulo, ExpressionType.[And], ExpressionType.[AndAlso], ExpressionType.[Or], ExpressionType.[OrElse], _
                    ExpressionType.LessThan, ExpressionType.LessThanOrEqual, ExpressionType.GreaterThan, ExpressionType.GreaterThanOrEqual, ExpressionType.Equal, ExpressionType.NotEqual, _
                    ExpressionType.Coalesce, ExpressionType.ArrayIndex, ExpressionType.RightShift, ExpressionType.LeftShift, ExpressionType.ExclusiveOr
                        Return Me.VisitBinary(DirectCast(exp, BinaryExpression))
                    Case ExpressionType.TypeIs
                        Return Me.VisitTypeIs(DirectCast(exp, TypeBinaryExpression))
                    Case ExpressionType.Conditional
                        Return Me.VisitConditional(DirectCast(exp, ConditionalExpression))
                    Case ExpressionType.Constant
                        Return Me.VisitConstant(DirectCast(exp, ConstantExpression))
                    Case ExpressionType.Parameter
                        Return Me.VisitParameter(DirectCast(exp, ParameterExpression))
                    Case ExpressionType.MemberAccess
                        Return Me.VisitMemberAccess(DirectCast(exp, MemberExpression))
                    Case ExpressionType.[Call]
                        Return Me.VisitMethodCall(DirectCast(exp, MethodCallExpression))
                    Case ExpressionType.Lambda
                        Return Me.VisitLambda(DirectCast(exp, LambdaExpression))
                    Case ExpressionType.[New]
                        Return Me.VisitNew(DirectCast(exp, NewExpression))
                    Case ExpressionType.NewArrayInit, ExpressionType.NewArrayBounds
                        Return Me.VisitNewArray(DirectCast(exp, NewArrayExpression))
                    Case ExpressionType.Invoke
                        Return Me.VisitInvocation(DirectCast(exp, InvocationExpression))
                    Case ExpressionType.MemberInit
                        Return Me.VisitMemberInit(DirectCast(exp, MemberInitExpression))
                    Case ExpressionType.ListInit
                        Return Me.VisitListInit(DirectCast(exp, ListInitExpression))
                    Case Else
                        Throw New Exception(String.Format("Unhandled expression type: '{0}'", exp.NodeType))
                End Select
            End Function
    
            Protected Overridable Function VisitBinding(ByVal binding As MemberBinding) As MemberBinding
                Select Case binding.BindingType
                    Case MemberBindingType.Assignment
                        Return Me.VisitMemberAssignment(DirectCast(binding, MemberAssignment))
                    Case MemberBindingType.MemberBinding
                        Return Me.VisitMemberMemberBinding(DirectCast(binding, MemberMemberBinding))
                    Case MemberBindingType.ListBinding
                        Return Me.VisitMemberListBinding(DirectCast(binding, MemberListBinding))
                    Case Else
                        Throw New Exception(String.Format("Unhandled binding type '{0}'", binding.BindingType))
                End Select
            End Function
    
            Protected Overridable Function VisitElementInitializer(ByVal initializer As ElementInit) As ElementInit
                Dim arguments As ReadOnlyCollection(Of Expression) = Me.VisitExpressionList(initializer.Arguments)
                If arguments IsNot initializer.Arguments Then
                    Return Expression.ElementInit(initializer.AddMethod, arguments)
                End If
                Return initializer
            End Function
    
            Protected Overridable Function VisitUnary(ByVal u As UnaryExpression) As Expression
                Dim operand As Expression = Me.Visit(u.Operand)
                If operand IsNot u.Operand Then
                    Return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method)
                End If
                Return u
            End Function
    
            Protected Overridable Function VisitBinary(ByVal b As BinaryExpression) As Expression
                Dim left As Expression = Me.Visit(b.Left)
                Dim right As Expression = Me.Visit(b.Right)
                Dim conversion As Expression = Me.Visit(b.Conversion)
                If left IsNot b.Left OrElse right IsNot b.Right OrElse conversion IsNot b.Conversion Then
                    If b.NodeType = ExpressionType.Coalesce AndAlso b.Conversion IsNot Nothing Then
                        Return Expression.Coalesce(left, right, TryCast(conversion, LambdaExpression))
                    Else
                        Return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method)
                    End If
                End If
                Return b
            End Function
    
            Protected Overridable Function VisitTypeIs(ByVal b As TypeBinaryExpression) As Expression
                Dim expr As Expression = Me.Visit(b.Expression)
                If expr IsNot b.Expression Then
                    Return Expression.TypeIs(expr, b.TypeOperand)
                End If
                Return b
            End Function
    
            Protected Overridable Function VisitConstant(ByVal c As ConstantExpression) As Expression
                Return c
            End Function
    
            Protected Overridable Function VisitConditional(ByVal c As ConditionalExpression) As Expression
                Dim test As Expression = Me.Visit(c.Test)
                Dim ifTrue As Expression = Me.Visit(c.IfTrue)
                Dim ifFalse As Expression = Me.Visit(c.IfFalse)
                If test IsNot c.Test OrElse ifTrue IsNot c.IfTrue OrElse ifFalse IsNot c.IfFalse Then
                    Return Expression.Condition(test, ifTrue, ifFalse)
                End If
                Return c
            End Function
    
            Protected Overridable Function VisitParameter(ByVal p As ParameterExpression) As Expression
                Return p
            End Function
    
            Protected Overridable Function VisitMemberAccess(ByVal m As MemberExpression) As Expression
                Dim exp As Expression = Me.Visit(m.Expression)
                If exp IsNot m.Expression Then
                    Return Expression.MakeMemberAccess(exp, m.Member)
                End If
                Return m
            End Function
    
            Protected Overridable Function VisitMethodCall(ByVal m As MethodCallExpression) As Expression
                Dim obj As Expression = Me.Visit(m.[Object])
                Dim args As IEnumerable(Of Expression) = Me.VisitExpressionList(m.Arguments)
                If obj IsNot m.[Object] OrElse args IsNot m.Arguments Then
                    Return Expression.[Call](obj, m.Method, args)
                End If
                Return m
            End Function
    
            Protected Overridable Function VisitExpressionList(ByVal original As ReadOnlyCollection(Of Expression)) As ReadOnlyCollection(Of Expression)
                Dim list As List(Of Expression) = Nothing
                Dim i As Integer = 0, n As Integer = original.Count
                While i < n
                    Dim p As Expression = Me.Visit(original(i))
                    If list IsNot Nothing Then
                        list.Add(p)
                    ElseIf p IsNot original(i) Then
                        list = New List(Of Expression)(n)
                        For j As Integer = 0 To i - 1
                            list.Add(original(j))
                        Next
                        list.Add(p)
                    End If
                    i += 1
                End While
                If list IsNot Nothing Then
                    Return list.AsReadOnly()
                End If
                Return original
            End Function
    
            Protected Overridable Function VisitMemberAssignment(ByVal assignment As MemberAssignment) As MemberAssignment
                Dim e As Expression = Me.Visit(assignment.Expression)
                If e IsNot assignment.Expression Then
                    Return Expression.Bind(assignment.Member, e)
                End If
                Return assignment
            End Function
    
            Protected Overridable Function VisitMemberMemberBinding(ByVal binding As MemberMemberBinding) As MemberMemberBinding
                Dim bindings As IEnumerable(Of MemberBinding) = Me.VisitBindingList(binding.Bindings)
                If bindings IsNot binding.Bindings Then
                    Return Expression.MemberBind(binding.Member, bindings)
                End If
                Return binding
            End Function
    
            Protected Overridable Function VisitMemberListBinding(ByVal binding As MemberListBinding) As MemberListBinding
                Dim initializers As IEnumerable(Of ElementInit) = Me.VisitElementInitializerList(binding.Initializers)
                If initializers IsNot binding.Initializers Then
                    Return Expression.ListBind(binding.Member, initializers)
                End If
                Return binding
            End Function
    
            Protected Overridable Function VisitBindingList(ByVal original As ReadOnlyCollection(Of MemberBinding)) As IEnumerable(Of MemberBinding)
                Dim list As List(Of MemberBinding) = Nothing
                Dim i As Integer = 0, n As Integer = original.Count
                While i < n
                    Dim b As MemberBinding = Me.VisitBinding(original(i))
                    If list IsNot Nothing Then
                        list.Add(b)
                    ElseIf b IsNot original(i) Then
                        list = New List(Of MemberBinding)(n)
                        For j As Integer = 0 To i - 1
                            list.Add(original(j))
                        Next
                        list.Add(b)
                    End If
                    i += 1
                End While
                If list IsNot Nothing Then
                    Return list
                End If
                Return original
            End Function
    
            Protected Overridable Function VisitElementInitializerList(ByVal original As ReadOnlyCollection(Of ElementInit)) As IEnumerable(Of ElementInit)
                Dim list As List(Of ElementInit) = Nothing
                Dim i As Integer = 0, n As Integer = original.Count
                While i < n
                    Dim init As ElementInit = Me.VisitElementInitializer(original(i))
                    If list IsNot Nothing Then
                        list.Add(init)
                    ElseIf init IsNot original(i) Then
                        list = New List(Of ElementInit)(n)
                        For j As Integer = 0 To i - 1
                            list.Add(original(j))
                        Next
                        list.Add(init)
                    End If
                    i += 1
                End While
                If list IsNot Nothing Then
                    Return list
                End If
                Return original
            End Function
    
            Protected Overridable Function VisitLambda(ByVal lambda As LambdaExpression) As Expression
                Dim body As Expression = Me.Visit(lambda.Body)
                If body IsNot lambda.Body Then
                    Return Expression.Lambda(lambda.Type, body, lambda.Parameters)
                End If
                Return lambda
            End Function
    
            Protected Overridable Function VisitNew(ByVal nex As NewExpression) As NewExpression
                Dim args As IEnumerable(Of Expression) = Me.VisitExpressionList(nex.Arguments)
                If args IsNot nex.Arguments Then
                    If nex.Members IsNot Nothing Then
                        Return Expression.[New](nex.Constructor, args, nex.Members)
                    Else
                        Return Expression.[New](nex.Constructor, args)
                    End If
                End If
                Return nex
            End Function
    
            Protected Overridable Function VisitMemberInit(ByVal init As MemberInitExpression) As Expression
                Dim n As NewExpression = Me.VisitNew(init.NewExpression)
                Dim bindings As IEnumerable(Of MemberBinding) = Me.VisitBindingList(init.Bindings)
                If n IsNot init.NewExpression OrElse bindings IsNot init.Bindings Then
                    Return Expression.MemberInit(n, bindings)
                End If
                Return init
            End Function
    
            Protected Overridable Function VisitListInit(ByVal init As ListInitExpression) As Expression
                Dim n As NewExpression = Me.VisitNew(init.NewExpression)
                Dim initializers As IEnumerable(Of ElementInit) = Me.VisitElementInitializerList(init.Initializers)
                If n IsNot init.NewExpression OrElse initializers IsNot init.Initializers Then
                    Return Expression.ListInit(n, initializers)
                End If
                Return init
            End Function
    
            Protected Overridable Function VisitNewArray(ByVal na As NewArrayExpression) As Expression
                Dim exprs As IEnumerable(Of Expression) = Me.VisitExpressionList(na.Expressions)
                If exprs IsNot na.Expressions Then
                    If na.NodeType = ExpressionType.NewArrayInit Then
                        Return Expression.NewArrayInit(na.Type.GetElementType(), exprs)
                    Else
                        Return Expression.NewArrayBounds(na.Type.GetElementType(), exprs)
                    End If
                End If
                Return na
            End Function
    
            Protected Overridable Function VisitInvocation(ByVal iv As InvocationExpression) As Expression
                Dim args As IEnumerable(Of Expression) = Me.VisitExpressionList(iv.Arguments)
                Dim expr As Expression = Me.Visit(iv.Expression)
                If args IsNot iv.Arguments OrElse expr IsNot iv.Expression Then
                    Return Expression.Invoke(expr, args)
                End If
                Return iv
            End Function
        End Class
    End Namespace
    
    
    Thursday, December 24, 2009 4:59 PM
  • Just Put Expand on the Inner Predicate.

     


    Dani Kaplan
    Thursday, March 17, 2011 9:01 AM
  • Awesome Dani, yes just doing:

    predicate = predicate.And(inner.Expand());
    

    works great, no need for the custom Rebinder or Visitor at all!

    • Proposed as answer by Yicen Tuesday, July 03, 2012 6:19 AM
    Friday, May 20, 2011 7:14 PM