38

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?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
dstr
  • 8,362
  • 12
  • 66
  • 106
  • possible duplicate of [Expression.GreaterThan fails if one operand is nullable type, other is non-nullable](http://stackoverflow.com/questions/2088231/expression-greaterthan-fails-if-one-operand-is-nullable-type-other-is-non-nulla) – nawfal Apr 23 '13 at 21:11

3 Answers3

74

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));
dstr
  • 8,362
  • 12
  • 66
  • 106
  • 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 May 15 '14 at 20:35
  • 2
    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! – JoeBrockhaus May 15 '14 at 20:52
  • 2
    @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. – Jon Hanna Apr 07 '17 at 00:12
  • Love you, this helped alot – Seabizkit Feb 27 '19 at 10:08
6

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)
Amin Golmahalleh
  • 3,585
  • 2
  • 23
  • 36
Leonel B.
  • 185
  • 3
  • 5
-3

You can check if a type is nullable by doing: if (typeof(T).Equals(typeof(Nullable<>)) I believe and then proceed to handle that specially. If you can invoke the GetValueOrDefault() method somehow, that would work, or programmbly create the comparison value to be of the same type maybe.

HTH.

Brian Mains
  • 50,520
  • 35
  • 148
  • 257