Working with nullable types in Expression Trees

19,839

Solution 1

I had to convert the value type to the column type using Expression.Convert:

Expression where = Expression.GreaterThanOrEqual(column, Expression.Convert(Expression.Constant(value), column.Type));

Solution 2

A type can be passed to the Expression.Constant function as a second argument. Something like typeof(int?) or, in the case of this question, column.Type.

e.g.

Expression.Constant(value, column.Type)
Share:
19,839
themiurge
Author by

themiurge

Updated on June 03, 2022

Comments

  • themiurge
    themiurge almost 2 years

    I have an extension method to dynamically filter Linq to Entities results using string values. It works fine until I use it to filter nullable columns. Here's my code:

    public static IOrderedQueryable<T> OrderingHelperWhere<T>(this IQueryable<T> source, string columnName, object value)
    {
        ParameterExpression table = Expression.Parameter(typeof(T), "");
        Expression column = Expression.PropertyOrField(table, columnName);
        Expression where = Expression.GreaterThanOrEqual(column, Expression.Constant(value));
        Expression lambda = Expression.Lambda(where, new ParameterExpression[] { table });
    
        Type[] exprArgTypes = { source.ElementType };
    
        MethodCallExpression methodCall = Expression.Call(typeof(Queryable), 
                                                          "Where", 
                                                          exprArgTypes, 
                                                          source.Expression, 
                                                          lambda);
    
        return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(methodCall);
    }
    

    Here's how I use it:

    var results = (from row in ctx.MyTable select row)
                  .OrderingHelperWhere("userId", 5);//userId is nullable column
    

    Here's the exception I'm getting when I use this for nullable table columns:

    The binary operator GreaterThanOrEqual is not defined for the types 'System.Nullable`1[System.Int32]' and 'System.Int32'

    I couldn't figured this out. What should I do?

  • JoeBrockhaus
    JoeBrockhaus almost 10 years
    I'm doing this very thing right now. I used Expression.Constant(value, column.Type) That said, my case is a bit more complicated because all my filter values are strings (not objects that should be a convertible type: int -> int?, bool -> bool?, etc). So not only do I need to create the expressions dynamically, but also the filter values in the types that match the columns.
  • JoeBrockhaus
    JoeBrockhaus almost 10 years
    Just changed back my code that was throwing this error before. Using Expression.Convert was FAR easier than dealing with checking if the type was Nullable (using reflection), and if so creating the Expression (as a return from my helper method) with an explicitly created Nullable<>). I simply cast the string to the desired value type (int, bool, etc), then Expression.Convert(Expression.Constant(castValue), columnType). boom. thanks for this find!
  • Jon Hanna
    Jon Hanna about 7 years
    @JoeBrockhaus why not just use the type with the Expresson.Constant whether it's nullable or not? Indeed, that's what I'd recommend as the answer here too.
  • Seabizkit
    Seabizkit about 5 years
    Love you, this helped alot
  • GilShalit
    GilShalit over 2 years
    This is a brilliant solution