LINQ扩展方法创建Where查询

时间:2018-07-16 13:09:31

标签: c# linq linq-to-entities linq-to-objects expressionvisitor

我正在尝试创建一种扩展方法,该方法可用于LINQ到对象和LINQ到实体来创建有效的Where查询。最终会涉及更多内容,但是开始时,我遇到一个问题,只是让方法获取lambda列选择并将其用作Contains()调用的基础。我已经能够使LINQ-to-Objects起作用,但是当我尝试将其用于LINQ-to-Entities时,就会出现问题。

这是对LINQ-to-Objects有效的方法:

public static IQueryable<T> WhereContains<T>(this IQueryable<T> query, Expression<Func<T, string>> column, IList<string> values)
{
    return query.Where(o => values.Contains(column.Compile().Invoke(o)));
}

如果这是针对Entity Framework运行的,我会收到一条异常说明

  

LINQ to Entities无法识别该方法...

我感觉这将需要使用ExpressionVisitor,但是我还无法弄清楚需要如何连接。有人能做到这一点吗?

更新:

我认为这不是重复的,因为xanatos提供的答案显示了无需使用ExpressionVisitor即可实现此目的的直接方法。

1 个答案:

答案 0 :(得分:1)

是的,您需要稍微修改Expression,但是不需要ExpressionVisitor。这要简单得多。

public static IQueryable<TSource> WhereContains<TSource, TResult>(this IQueryable<TSource> query, Expression<Func<TSource, TResult>> column, IList<TResult> values)
{
    MethodInfo iListTResultContains = typeof(ICollection<>).MakeGenericType(typeof(TResult)).GetMethod("Contains", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(TResult) }, null);

    var contains = Expression.Call(Expression.Constant(values), iListTResultContains, column.Body);

    var lambda = Expression.Lambda<Func<TSource, bool>>(contains, column.Parameters);

    return query.Where(lambda);
}

请注意,我已经对其进行了扩展,以涵盖string