Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect where applied to IQueryable<T>

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"));
like image 204
Rodrigo Juarez Avatar asked Oct 26 '11 12:10

Rodrigo Juarez


3 Answers

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).

like image 78
casperOne Avatar answered Sep 29 '22 00:09

casperOne


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")
like image 33
xanatos Avatar answered Sep 29 '22 00:09

xanatos


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.

like image 20
Jon Hanna Avatar answered Sep 29 '22 00:09

Jon Hanna