0

Implementing a provider for this is not that difficult:

var query = from foo in someContext.Foos
                   where foo.Bar == "bar" && foo.Gaz > 4
                   select foo;

But if I chain together two operators like so:

var chained1 = (from foo in someContext.Foos
                         where foo.Bar == "bar"
                         select foo)
                         .Where(f => f.Gaz > 4);

or if I did this:

var chained2 = chained1.Take(10);

How would I implement this?

In evaluating the current method call or operator, in the VisitMethodCall, I visit the instance / object / expression on which the method call is made. That should call VisitConstant for evaluating / translating / re-writing that instance expression.

Then, in the VisitConstant if I do this:

if (typeof(IQueryable).IsAssignableFrom(node.Type))
{
    _builder.Append((node.Value as IQueryable).ToString());
}

it doesn't work.

How do I get the query text for the previously built query?

Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336
  • Whether you use query syntax or method syntax, or whether or not the operations are stored in intermediate variables before subsequent operations are call all has literally *zero* affect on the final `IQueryable`. – Servy Jan 16 '15 at 16:22
  • Can you add how `somecontext` is being created? – Ryan Gates Jan 16 '15 at 16:23
  • 3
    How you implement a query provider is going to depend entirely on what you are creating a provider for, how you want it to work, what operations you want to support, how you want various LINQ operations to be translated into that language, etc. As it is, the question is nowhere near answerable. – Servy Jan 16 '15 at 16:23
  • @Servy: While what you say is somewhat true, the specifics of the destination / target DSL in which the query is to be translated are not at all relevant to this question. This question can easily be answered without that knowledge. The sum and substance of implementing the provider is the same whatever the target DSL be. – Water Cooler v2 Jan 16 '15 at 16:29
  • 1
    @WaterCoolerv2 No...it's not. This question is completely unanswerable without knowing a *huge* amount of information about what else your query provider is doing, and what exactly you want it to do. And were you to actually include all of that information it would almost certainly make the question Too Broad. An `IQueryable` can do pretty much anything, as it only restricts the public API; why your implementation doesn't do what you want it to do is something we could only *begin* to discuss if you *showed us your implementation*. – Servy Jan 16 '15 at 16:32
  • @WaterCoolerv2: The premise of this question says that it's "simple" to do a `.Where().Select()`, but then you have no idea how to apply another `.Where()` to the result of the `.Select()`? Why are the first two calls simple and the third one difficult? – StriplingWarrior Jan 16 '15 at 16:35
  • Use Entity Framework :) – reggaeguitar Jan 16 '15 at 16:39
  • On second thoughts, I do realize that a lot of context is missing from this question. May be I'll find the answer out another way. Posting all of the code and explaining the question or narrowing its scope down is going to take as much effort and time as if I researched it myself. – Water Cooler v2 Jan 16 '15 at 16:40
  • @reggaeguitar There are all sorts of data sources that one may want to connect to that EF doesn't support, and all sorts of functionality that EF doesn't support that one might want to have in their own query provider. – Servy Jan 16 '15 at 16:44
  • Have you taken a look at http://msdn.microsoft.com/en-us/library/vstudio/bb546158%28v=vs.110%29.aspx ? – Erti-Chris Eelmaa Jan 16 '15 at 16:56
  • @ChrisEelmaa: Yes, that's the simple stuff. That's even simpler than the simple stuff. That's where you start. That's ground zero. – Water Cooler v2 Jan 16 '15 at 16:57

1 Answers1

1

This is a good series which can get you going: http://blogs.msdn.com/b/mattwar/archive/2007/07/31/linq-building-an-iqueryable-provider-part-ii.aspx

In your example, this is a pseudo-code what should be done (for your Take example):

VisitMethodCallExpression gets a call on an expression with method Take, you'll have to do:

_sb.Append("SELECT * FROM (");
Visit(..chained1..); // generate query for chained1 to _sb (recursively)
_sb.Append(") LIMIT "); 
VisitConstant(TakeMethodInfo.LambdaExpression);

As you can see, this will work, but it leads to a redudant subqueries. YOu can read more about these here: http://blogs.msdn.com/b/mattwar/archive/2008/01/16/linq-building-an-iqueryable-provider-part-ix.aspx

Good luck.

Erti-Chris Eelmaa
  • 25,338
  • 6
  • 61
  • 78
  • Thanks, Chris. Over the last year, I've gone through Matt's entire series and practiced and even written a custom LINQ provider. I am not able to articulate my question and it does not make itself very clear without the information I have not provided, perhaps. I am actually thinking and I think thinking more will help me reach the solution I am after. I think I am almost there. I should be posting an answer to my own question once I have it in my mind. – Water Cooler v2 Jan 16 '15 at 18:13
  • I really appreciate your help, though. :-) – Water Cooler v2 Jan 16 '15 at 18:13