检测应用于IQueryable 的位置
如何检测IQueryable
是否应用了where
filter?
在这段代码中,我需要以编程方式知道queryFiltered
有一个应用于它的地方而query
没有
IQueryable query = Context.Customers; IQueryable queryFiltered = Context.Customers .Where(c=>c.Name.Contains("ABC"));
您必须解析从IQueryable
实现上的Expression
属性返回的Expression
。
您必须查询在爬行Expression
树时调用的Queryable.Where
方法 。
另请注意,虽然Queryable.Where
将是检测where
filter的最常用方法,但查询语法允许使用其他实现(取决于using
指令中使用的名称空间); 如果你有一些不使用Queryable.Where
扩展方法的东西那么你必须明确地寻找它(或者使用更通用的过滤方法来过滤一个带有IQueryable
的Where
方法并返回一个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的东西,但它似乎更简单。