How do I get the query text of the IQueryable<T> instance on which this operator is called?

754 Views Asked by At

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?

1

There are 1 best solutions below

2
On

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.