How can I detect if a IQueryable<T>
has a where
filter applied?
In this code, I need to know programmatically that queryFiltered
has a where
applied to it and query
doesn't
IQueryable<Customer> query = Context.Customers;
IQueryable<Customer> queryFiltered = Context.Customers
.Where(c=>c.Name.Contains("ABC"));
You will have to parse the Expression
that is returned from the Expression
property on the IQueryable<T>
implementation.
You'll have to query for the Queryable.Where
method being called as you crawl the Expression
tree.
Also note that while Queryable.Where
is going to be the most common way to detect a where
filter, query syntax allows for other implementations to be used (depending on what namespaces are used in the using
directives); if you have something that is not using the Queryable.Where
extension method then you'll have to look for that explicitly (or use a more generic method of filtering for a Where
method that takes an IQueryable<T>
and returns an IQueryable<T>
).
The ExpressionVisitor
class (as pointed out by xanatos) provides a very easy way of crawling the Expression
tree, I highly recommend using that approach as a base for processing your Expression
tree.
Of note is that ExpressionVisitor
class implementations are required to store and expose state on the class level. Because of that, it would be best (IMO) to create internal classes that perform the action one-time and then have a public method which creates a new instance of the ExpressionVisitor
every time; this will help with dealing with mutating state, and if done properly, will allow the method to be thread-safe as well (if that is a concern of yours).
If you are using C# 4.0 you can use this sample code: Get all 'where' calls using ExpressionVisitor
It's based on ExpressionVisitor
. It "visits" the various elements of a IQueryable<T>
to find the Where
parts. It seems simple enough.
If you are on C# = 3.5, you can use the ExpressionVisitor
sample from MSDN's How to: Implement an Expression Tree Visitor PLUS the WhereFinder
from the previous link (they work correctly together, just tested)
To use the code:
var wf = new WhereFinder();
var wheres = wf.GetWhere(query.Expression);
if (wheres.Any())
{
// There are Where in the query!
}
If you are (correctly) as much paranoid as Rune FS
, to the WereFinder.VisitMethodCall
, change the if
to
if (expression.Method.Name == "Where" && expression.Method.DeclaringType.FullName == "System.Linq.Queryable")
The simplest way is call q.Expression.ToString().Contains(".Where(")
. As you can see, query.Expression.ToString().Contains(".Where(")
returns false while queryFiltered.Expression.ToString().Contains(".Where(")
returns true.
You may need more complexity than that if you count other expressions as "filtering", but that is true with the expression visitor approach too.
There's something rather hacky about this I'll grant you, but it does seem much simpler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With