Search code examples
linqentity-frameworklambdalinq-to-entitieslinq-expressions

Expression Trees in Linq To Entities


I'm trying to make an extension method that takes in an expression that points to a property on an entity, and a constant string to compare it to using String.Contains, that first checks whether the string is null or empty, and applies the filter only if the string has a value. This is my first dabble in Expression Trees though, so I'm not really sure what's going on, and I now have an exception which I'm not sure how to cure...

I'm at this so far:

<System.Runtime.CompilerServices.Extension()>
    Public Function CheckAndFilter(Of T)(source As System.Linq.IQueryable(Of T), expressionField As System.Linq.Expressions.Expression(Of System.Func(Of T, String)), compareTo As String) As IQueryable(Of T)


        If String.IsNullOrEmpty(compareTo) Then
            Return source
        Else
            Dim memberExp As Expressions.MemberExpression = DirectCast(expressionField.Body, Expressions.MemberExpression)

            Dim param = Expressions.Expression.Parameter(GetType(T))
            Dim method As Reflection.MethodInfo = GetType(String).GetMethod("Contains")

            Dim compareToExpression = Expressions.Expression.Constant(compareTo)
            Dim finalExpr = Expressions.Expression.Call(memberExp, method, compareToExpression)

            Dim lambda = Expressions.Expression.Lambda(Of Func(Of T, Boolean))(finalExpr, param)
            Return source.Where(lambda)
        End If
    End Function

I'm calling it like this, against a DbContext where I have a Customer entity with a FirstName string property:

Dim results = repository.Customers.CheckAndFilter(Function(c) c.FirstName, searchText)

And the exception is:

{"The parameter 'c' was not bound in the specified LINQ to Entities query expression."}

Any thoughts?


Solution

  • A ha!

    It's because I've declared a new parameter rather than re-using the one passed in via the expression...

    <System.Runtime.CompilerServices.Extension()>
    Public Function CheckAndFilter(Of T)(source As System.Linq.IQueryable(Of T), expressionField As System.Linq.Expressions.Expression(Of System.Func(Of T, String)), compareTo As String) As IQueryable(Of T)
    
    
        If String.IsNullOrEmpty(compareTo) Then
            Return source
        Else
            Dim memberExp As Expressions.MemberExpression = DirectCast(expressionField.Body, Expressions.MemberExpression)
    
            Dim method As Reflection.MethodInfo = GetType(String).GetMethod("Contains")
    
            Dim compareToExpression = Expressions.Expression.Constant(compareTo)
            Dim finalExpr = Expressions.Expression.Call(memberExp, method, compareToExpression)
    
            Dim lambda = Expressions.Expression.Lambda(Of Func(Of T, Boolean))(finalExpr, expressionField.Parameters)
            Return source.Where(lambda)
        End If
    End Function