2

I'm trying to create a generic function to build a Linq expression from a list of Telerik grid filters. I'm trying to stay clear of dynamic Linq. Because I don't know the type that I'm building the expression for, I'm attempting to use reflection in the lambda functions to refer to a property, but my results are never filtered. The call to my helper function to get the property value is never called though it does hit the "Add" lines. Putting the reflection in line (such as the "GreaterThan" below) doesn't make a difference. here is my code:

Public Shared Function buildRadFilter(Of T)(ByVal filterExpression As List(Of GridFilterExpression)) As Expressions.Expression(Of Func(Of T, Boolean))
        Dim returnPred = PredicateBuilder.True(Of T)()

        For Each exp As GridFilterExpression In filterExpression
            Dim iExp = exp
            Dim doDefault = False
            Select Case iExp.FilterFunction
                Case "Contains"
                    returnPred.And(Function(x) DirectCast(propVal(x, iExp.FieldName), String).Contains(iExp.FieldValue))
                Case "DoesNotContain"
                    returnPred.And(Function(x) Not DirectCast(propVal(x, iExp.FieldName), String).Contains(iExp.FieldValue))
                Case "StartsWith"
                    returnPred.And(Function(x) DirectCast(propVal(x, iExp.FieldName), String).StartsWith(iExp.FieldValue))
                Case "EndsWith"
                    returnPred.And(Function(x) DirectCast(propVal(x, iExp.FieldName), String).EndsWith(iExp.FieldValue))
                Case "EqualTo"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) = iExp.FieldValue)
                Case "NotEqualTo"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) <> iExp.FieldValue)
                Case "GreaterThan"
                    'returnPred.And(Function(x) propVal(x, iExp.FieldName) > iExp.FieldValue)
                    returnPred.And(Function(x) x.GetType().GetProperty(iExp.FieldName).GetValue(x, Nothing))
                Case "GreaterThanOrEqualTo"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) >= iExp.FieldValue)
                Case "LessThan"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) < iExp.FieldValue)
                Case "LessThanOrEqualTo"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) <= iExp.FieldValue)
                Case "IsEmpty"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) = "")
                Case "NotIsEmpty"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) <> "")
                Case "IsNull"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) Is Nothing)
                Case "NotIsNull"
                    returnPred.And(Function(x) propVal(x, iExp.FieldName) IsNot Nothing)
                Case "Between"
                    Dim vals As String() = iExp.FieldValue.Split(" ")
                    If vals.Length > 1 Then
                        returnPred.And(Function(x) propVal(x, iExp.FieldName) >= vals(0) AndAlso propVal(x, iExp.FieldName) <= vals(1))
                    Else
                        doDefault = True
                        Exit Select
                    End If
                Case "NotBetween"
                    Dim vals As String() = iExp.FieldValue.Split(" ")
                    If vals.Length > 1 Then
                        returnPred.And(Function(x) propVal(x, iExp.FieldName) < vals(0) OrElse propVal(x, iExp.FieldName) > vals(1))
                    Else
                        doDefault = True
                        Exit Select
                    End If
                Case Else
                    doDefault = True
                    Exit Select
            End Select
            If doDefault Then
                returnPred.And(Function(x) DirectCast(propVal(x, iExp.FieldName), String).StartsWith(iExp.FieldValue))
            End If
        Next

        Return returnPred
    End Function

    'only works for scalar values
    Public Shared Function propVal(ByRef obj As Object, ByVal name As String) As Object
        Return obj.GetType().GetProperty(name).GetValue(obj, Nothing)
    End Function

Thank you in advance for any help you may be able to offer.

2
  • Here's a link to fix the "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." bug. Just a note, it's just .AsExpandable not .AsExpandable() (at least for vb.net). Once I have a final solution for this I will post it again, because I haven't found something like this anywhere. Commented May 18, 2011 at 16:51
  • As promised, here is a link to my final solution. It turned out to be a huge pain because you can't use a Type variable as a parameter in ctype or DirectCast in vb and you can't do linq comparisons on a an object and a nullable object of the same type. If someone has a better algorithm feel free to post it. Commented May 23, 2011 at 16:56

1 Answer 1

3

The reason why is the And predicate creates a new expression which you are not saving. It doesn't modify the existing one in place. You need to switch every returnPred.And line to

returnPred = returnPred.And(...
Sign up to request clarification or add additional context in comments.

2 Comments

You're absolutely right - I'm still new to Linq. After applying your fix though, I get the error, "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." Do you know of any way around this?
@dtryan I'm not familiar enough with LINQ to Entities to know the answer to that. I believe though it's because there's no way to translate that to a Entity call. If you ask another Q though there's bound to be a LINQ to Entity user who will know the answer ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.