Udostępnij za pośrednictwem


The code pattern of doing everything in IQueryProvider…

(Rambling) I’m taking another short foray into IQueryable land. From my learnings last time, In brief, I realized that IQueryable = Expression Tree, + QueryProvider, and that if you take a lazy approach to implementing IQueryable, then all the real work is happening inside QueryProvider.Execute(), where it can just retranslate the entire expression tree you built up, and execute it.

But once I start down that path, I have to think about how to implement QueryProvider.Execute(). So here is what my thoughts looked like:

1) Visit current expression node.
2) You either recognize this as something which has ‘native’ expression semantics, or something which is just a standard LINQism which will need to be run as a post-step after you get the results your backend can give you. Either way, you might need to modify the ‘native’ expression you request your backend to execute.

Example: The .Single() LINQ operator can easily be run as a client side post-processing step after requesting the first 2 elements of the sequence, if that’s something your backend supports.

3) If you need to modify the query you’re doing against backend, then for Where,Select,etc … then you recursively ‘evaluate’ some inner node to build up a logical description of the query your backend will execute for the inner node, then wrap that query in some higher level logical description of the composite query.

4) If you’ve found something that isn’t supported by the backend, like First(), Single() but that you have client workarounds for, you could go ahead and execute the expression against the backend now. But what if that First() was inside yet something else? Would that be premature evaluation?

So let’s see… basically inside Execute() you do a gigantic visit to translate a general linq expression tree into a custom expression tree that your backend can execute natively without further validation/translation… and then at, the top level of Execute(), something will be found to force that tree to be evaluated… and runs a few client side expressions afterwards. But the meat of the work is translating a LINQ expression tree into a myExpressionTree….

Then I think wait… is it really easier to do that translation as a post-process? Why don’t we do it online, as the expression is built, in the IQueryable, itself?

So…

Basically, I’ve run around in a complete circle of self-doubt, and decided that it might be cleaner not to go with the trivial IQueryable implementation after all. Because it saves me from having to re-implement a deferred execution + visitor pattern in IQueryProvider.

So, that’s the next avenue to explore! Which brings todays rambling to an end. If it made sense to you, you’re welcome.