创建 Where 查询的 LINQ 扩展方法

Posted

技术标签:

【中文标题】创建 Where 查询的 LINQ 扩展方法【英文标题】:LINQ extension method to create Where query 【发布时间】:2018-12-24 01:09:45 【问题描述】:

我正在尝试创建一个可用于 LINQ-to-Object 和 LINQ-to-Entities 的扩展方法,以创建功能正常的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)));

如果这是针对实体框架运行的,我会得到一个异常说明

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

我觉得这需要使用ExpressionVisitor,但我无法弄清楚它需要如何连接。有没有人能够做到这一点?

更新:

我认为这不是重复的,因为 xanatos 提供的答案显示了在不使用 ExpressionVisitor 的情况下实现这一目标的直接方法。

【问题讨论】:

你说得对,需要这样的东西。 LINQKit 的 .AsExpandable() 将在这里工作。以前有人问过这个问题,我看看能不能找到详细的答案。 我认为o. 不应该在那里(o =&gt; o.values... 应该是o =&gt; values... 你在额外的“o.”上是对的。我在系统之间转录。已更正上面的示例。 @xanatos 这个问题在什么方面不是它作为副本而关闭的问题的副本? @Servy 另一个问题是关于两个表达式的组合......这个只是将一个插入另一个。唯一共同的部分似乎是使用Contains 作为方法。如果您查看其他问题的回复,则必须使用ExpressionVisitor 【参考方案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

【讨论】:

完美,谢谢。由于我对方法内部数据所做的其他限制,我无法使用通用结果,但您提供的示例说明了语法。我需要深入研究表达式构建助手。

以上是关于创建 Where 查询的 LINQ 扩展方法的主要内容,如果未能解决你的问题,请参考以下文章

Linq

如何使用 linq lambda 扩展方法执行带有 where 子句的左外连接

使用 Linq 的 Where/Select 过滤掉 null 并将类型转换为不可为 null 不能做成扩展方法

LINQ使用

LINQ中的扩展方法

扩展方法和Enumerable