在表达式树中使用可空类型

38

我有一个扩展方法,可以使用字符串值动态过滤Linq to Entities结果。它在过滤可空列时无法正常工作。以下是我的代码:

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);
}

这是我使用它的方法:

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

我使用可空表列时遇到了以下异常:

二元运算符GreaterThanOrEqual未定义于类型“System.Nullable`1[System.Int32]”和“System.Int32”之间

我不知道该怎么办,求教。


3个回答

75

我必须使用Expression.Convert将值类型转换为列类型:

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

我现在正在做这件事情。我使用了 Expression.Constant(value, column.Type)。话虽如此,我的情况有点更加复杂,因为我所有的过滤值都是字符串(不是应该是可转换类型的对象:int -> int?, bool -> bool?等)。因此,我不仅需要动态创建表达式,还需要创建与列匹配的类型中的过滤值。 - JoeBrockhaus
2
刚刚修改了我的代码,之前一直出现错误。使用 Expression.Convert 比起通过反射检查类型是否为 Nullable(如果是,则创建一个表达式作为帮助方法的返回值,并显式创建 Nullable<>),要简单得多。我只需将字符串强制转换为所需的值类型(int、bool 等),然后使用 Expression.Convert(Expression.Constant(castValue), columnType) 即可。太棒了,感谢这个发现! - JoeBrockhaus
2
@JoeBrockhaus为什么不直接使用带有Expresson.Constant的类型,无论它是否可为空?实际上,这也是我在此处推荐的答案。 - Jon Hanna
爱你,这帮了很多忙。 - Seabizkit

6

第二个参数可以传递给 Expression.Constant 函数的是一个类型。例如,像 typeof(int?) 这样的类型或者在这个问题中使用的 column.Type

例如:

Expression.Constant(value, column.Type)

这是一个非常出色的解决方案。 - GilShalit

-3
你可以通过以下方式检查类型是否可为空:if (typeof(T).Equals(typeof(Nullable<>)),然后特殊处理。如果你能以某种方式调用GetValueOrDefault()方法,那就可以工作了,或者可能以编程方式创建相同类型的比较值。

希望对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接