检测应用于IQueryable 的位置

如何检测IQueryable是否应用了wherefilter?

在这段代码中,我需要以编程方式知道queryFiltered有一个应用于它的地方而query没有

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

您必须解析从IQueryable实现上的Expression属性返回的Expression

您必须查询在爬行Expression树时调用的Queryable.Where方法 。

另请注意,虽然Queryable.Where将是检测wherefilter的最常用方法,但查询语法允许使用其他实现(取决于using指令中使用的名称空间); 如果你有一些不使用Queryable.Where扩展方法的东西那么你必须明确地寻找它(或者使用更通用的过滤方法来过滤一个带有IQueryableWhere方法并返回一个IQueryable )。

ExpressionVisitor类 ( 由xanatos指出 )提供了一种非常简单的爬行Expression树的方法,我强烈建议使用该方法作为处理Expression树的基础。

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

如果您使用的是C#4.0,则可以使用此示例代码: 使用ExpressionVisitor获取所有“where”调用

它基于ExpressionVisitor 。 它“访问” IQueryable的各种元素以找到Where部分。 看起来很简单。

如果您使用的是C#= 3.5,则可以使用MSDN中的ExpressionVisitor示例如何:实现表达式树访问者 PLUS来自上一个链接的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") 

最简单的方法是调用q.Expression.ToString().Contains(".Where(") 。正如你所看到的, query.Expression.ToString().Contains(".Where(")queryFiltered.Expression.ToString().Contains(".Where(")返回false queryFiltered.Expression.ToString().Contains(".Where(")返回true。

如果将其他表达式视为“过滤”,则可能需要更多的复杂性,但对于表达式访问者方法也是如此。

我会给你一些相当hacky的东西,但它似乎更简单。