【问题标题】:Detect where applied to IQueryable<T>检测应用到 IQueryable<T> 的位置
【发布时间】:2011-10-26 12:43:16
【问题描述】:

如何检测IQueryable&lt;T&gt; 是否应用了where 过滤器?

在这段代码中,我需要以编程方式知道queryFiltered 应用了wherequery 没有

IQueryable<Customer> query = Context.Customers;
IQueryable<Customer> queryFiltered = Context.Customers
                                            .Where(c=>c.Name.Contains("ABC"));

【问题讨论】:

  • 为什么?提供更多上下文可能有助于给出更好的答案

标签: c# linq entity-framework


【解决方案1】:

您必须解析从 Expression property 上的 IQueryable&lt;T&gt; 实现返回的 Expression

您必须在抓取 Expression 树时查询被调用的 Queryable.Where method

还请注意,虽然Queryable.Where 将是检测where 过滤器的最常用方法,但查询语法允许使用其他实现(取决于using directives 中使用的命名空间);如果你有一些没有使用 Queryable.Where 扩展方法的东西,那么你必须明确地寻找它(或者使用更通用的过滤方法来过滤 Where 方法,该方法采用 IQueryable&lt;T&gt; 并返回 @987654339 @)。

ExpressionVisitor class(如pointed out by xanatos)提供了一种非常简单的爬取Expression 树的方法,我强烈建议使用该方法作为处理Expression 树的基础。

值得注意的是ExpressionVisitor 类实现需要在类级别上存储和公开状态。正因为如此,最好(IMO)创建一次执行操作的内部类,然后有一个公共方法,每次都创建一个ExpressionVisitor 的新实例;这将有助于处理变异状态,如果处理得当,也将允许该方法是线程安全的(如果这是您所关心的)。

【讨论】:

    【解决方案2】:

    如果您使用的是 C# 4.0,您可以使用以下示例代码:Get all 'where' calls using ExpressionVisitor

    它基于ExpressionVisitor。它“访问”IQueryable&lt;T&gt; 的各个元素以找到Where 部分。看起来很简单。

    如果您使用的是 C# = 3.5,则可以使用 MSDN 的 How to: Implement an Expression Tree Visitor 中的 ExpressionVisitor 示例以及上一个链接中的 WhereFinder(它们可以一起正常工作,刚刚经过测试)

    使用代码:

    var wf = new WhereFinder();
    var wheres = wf.GetWhere(query.Expression);
    
    if (wheres.Any())
    {
        // There are Where in the query!
    }
    

    如果您(正确地)像Rune FS 一样偏执,请更改为WereFinder.VisitMethodCall,将if 更改为

    if (expression.Method.Name == "Where" && expression.Method.DeclaringType.FullName == "System.Linq.Queryable")
    

    【讨论】:

    • 它基本上所做的只是搜索一个名为“where”的方法,该方法很容易被另一个名为 where 的非过滤方法所欺骗
    • @RuneFS 已更正。但我确实认为您应该对原始 Q/A 进行更正:-)
    • 原始帖子涉及一个特定场景,其中表达式树是预先知道的,OP 希望将两个 where 子句提取为表达式。
    【解决方案3】:

    最简单的方法是致电q.Expression.ToString().Contains(".Where(")。如您所见,query.Expression.ToString().Contains(".Where(") 返回 false 而 queryFiltered.Expression.ToString().Contains(".Where(") 返回 true。

    如果您将其他表达式视为“过滤”,您可能需要比这更复杂的情况,但表达式访问者方法也是如此。

    我会告诉你,这有点奇怪,但看起来确实要简单得多。

    【讨论】:

    • new int[] { }.AsQueryable().Select(p =&gt; ".Where(").ToString().Contains(".Where(") :-)
    • @xanatos 现在这简直是反常的! :)
    • @RuneFS 是的,很清楚。您可以通过使用其全名(因此 Queryable.Where`number)更好地过滤 Where
    • 使用 ExpressionVisitor 方法并匹配 IIRC 类型可能会更好,因此它可以在无法做到的地方变得防弹。对于真正复杂的表达式,它也应该更快。我确实说过我的很hacky,不是吗:) 它仅用于比较,因为ExpressionVisitor方法已经在答案中给出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2017-02-22
    • 2020-12-22
    • 2013-09-03
    • 1970-01-01
    • 2018-12-26
    相关资源
    最近更新 更多