Re: [re-motion-users] re-linq. How to extract required expression.

78 views
Skip to first unread message

Fabian Schmied

unread,
Aug 16, 2012, 11:03:03 AM8/16/12
to re-moti...@googlegroups.com
Hi Alexandr,

When you use re-linq to parse a query, it translates the original LINQ
IQueryable into a QueryModel, which more closely reflects the query
structure as it would be written in C#. So, to solve your problem
using re-linq, you'd probably need to write three steps:

- When given a QueryModel, analyze it (e.g., using a subclass of
QueryModelVisitorBase) to find whether you can or cannot execute it.
- If you cannot execute it, traverse the Expressions within the
QueryModel (e.g., using QueryModel.TransformExpressions and a subclass
of ExpressionTreeVisitor) to find all SubQueryExpressions that you can
execute. Execute those, then replace the SubQueryExpressions with a
ConstantExpression containing the result.
- Then, take the QueryModel and either "interpret" it in memory, or
build a Linq-to-SQL expression tree from it, compile it, and run it.

This is probably going to be quite complex, but if you have any
specific questions about how to implement one of these steps using
re-linq, you can of course ask here.

Best regards,
Fabian

On Thu, Aug 16, 2012 at 1:45 PM, Alexandr Nikitin
<nikitin.a...@gmail.com> wrote:
> Hi guys!
> I'm new to re-linq and in need for a help.
>
> I'm writing a Linq provider to a web site API.
> It retrieves collection of "objects" by http request.
> For example by request "GetModels.php" it retrieves xml with all "Model" objects.
>
> I query my provider by this query:
>
> var query = from m in Models select m.Name where m.Id = 15
>
> I want my provider to do such things.
> 1. To extract the query that it can execute.
> According to example:
>
> from m in Models select m
>
> 2. Extract the query that it can't execute and apply it to executed query (retrieved results)
> According to example:
>
> from m in (result data) select m.Name where m.Id = 15
>
> How can I extract such queries?
> Appreciate any help.
>
> --
> You received this message because you are subscribed to the Google Groups "re-motion Users" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/re-motion-users/-/Oedvwiy0xPkJ.
> To post to this group, send email to re-moti...@googlegroups.com.
> To unsubscribe from this group, send email to re-motion-use...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/re-motion-users?hl=en.
>

Alexandr Nikitin

unread,
Aug 16, 2012, 3:56:19 PM8/16/12
to re-moti...@googlegroups.com
Thank you, Fabian!

"- If you cannot execute it, traverse the Expressions within the 
QueryModel (e.g., using QueryModel.TransformExpressions and a subclass
of ExpressionTreeVisitor) to find all SubQueryExpressions that you can
execute. Execute those, then replace the SubQueryExpressions with a
ConstantExpression containing the result."

I have difficulties with it.
Could you provide a simple example of this step please.

Fabian Schmied

unread,
Aug 17, 2012, 2:23:28 AM8/17/12
to re-moti...@googlegroups.com
Hi,

> "- If you cannot execute it, traverse the Expressions within the
> QueryModel (e.g., using QueryModel.TransformExpressions and a subclass
> of ExpressionTreeVisitor) to find all SubQueryExpressions that you can
> execute. Execute those, then replace the SubQueryExpressions with a
> ConstantExpression containing the result."
>
> I have difficulties with it.
> Could you provide a simple example of this step please.

I can give you some pseudo-code from my head:

class EvaluatableQueryExpressionFinder : ExpressionTreeVisitor
{
override Expression VisitSubQueryExpression (SubQueryExpression expr)
{
if (YourLogic.CanExecuteByHttpRequest (expr.QueryModel))
return Expression.Constant (YourLogic.ExecuteByHttpRequest
(expr.QueryModel), expr.Type);
else
return base.VisitSubQueryExpression (expr);
}
}

class YourQueryExecutor: IQueryExecutor
{
...

override IEnumerable<T> ExecuteCollectionQuery<T> (QueryModel queryModel)
{
if (YourLogic.CanExecuteByHttpRequest (expr.QueryModel))
return (IEnumerable<T>) YourLogic.ExecuteByHttpRequest (expr.QueryModel);
else
{
queryModel.TransformExpressions (expr => new
EvaluatableQueryExpressionFinder ().VisitExpression (expr));
return (IEnumerable<T>) YourCodeEvaluatingRemainingQueryModel
(queryModel);
}
}
}

You'll have to implemen the exact logic yourself.

Of course, this can get arbitrarily complex. For example, what if you
have the following query:

var query = from x in (from m in Models select m.Name).Count() where
x.Id = 15 select x

re-linq represents this query as a QueryModel (from x in ... where
x.Id = 15 select x) with a second QueryModel in its from clause ((from
m in Models select m.Name).Count()). You can see this by calling
ToString on the QueryModel.

Now, say, you can execute the "from m in Models select m.Name" part by
HTTP request, but not the Count operator. If you want to support that
case, you have two choices: Either analyze the QueryModel before
executing it, putting the "from m in Models select m.Name" into its
own subquery:

from x in (from y in (from m in Models select m.Name) select
y).Count() where x.Id = 15 select x

Now, apply the pseudo-code I've given above, and it should work nicely.

Or implement the YourLogic.ExecuteByHttpRequest method I've used
within the pseudo-code to manually evaluate all the result operators
it can't map to the HTTP request.

Best regards,
Fabian

> On Thursday, August 16, 2012 2:45:44 PM UTC+3, Alexandr Nikitin wrote:
>>
>> Hi guys!
>> I'm new to re-linq and in need for a help.
>>
>> I'm writing a Linq provider to a web site API.
>> It retrieves collection of "objects" by http request.
>> For example by request "GetModels.php" it retrieves xml with all "Model"
>> objects.
>>
>> I query my provider by this query:
>>
>> var query = from m in Models select m.Name where m.Id = 15
>>
>> I want my provider to do such things.
>> 1. To extract the query that it can execute.
>> According to example:
>>
>> from m in Models select m
>>
>> 2. Extract the query that it can't execute and apply it to executed query
>> (retrieved results)
>> According to example:
>>
>> from m in (result data) select m.Name where m.Id = 15
>>
>> How can I extract such queries?
>> Appreciate any help.
>
> --
> You received this message because you are subscribed to the Google Groups
> "re-motion Users" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/re-motion-users/-/2ptV28zNNW0J.

Alexandr Nikitin

unread,
Aug 17, 2012, 7:56:08 AM8/17/12
to re-moti...@googlegroups.com
Thank you Fabian!
It's going more clear now.

"- Then, take the QueryModel and either "interpret" it in memory, or 
build a Linq-to-SQL expression tree from it, compile it, and run it."

One more stupid question about this step:
How to execute QueryModel?

Fabian Schmied

unread,
Aug 20, 2012, 7:10:17 AM8/20/12
to re-moti...@googlegroups.com
> Thank you Fabian!
> It's going more clear now.
>
> "- Then, take the QueryModel and either "interpret" it in memory, or
> build a Linq-to-SQL expression tree from it, compile it, and run it."
>
> One more stupid question about this step:
> How to execute QueryModel?

Well, as I said: either interpret it in memory, or build a Linq-to-SQL
expression tree from it (i.e., call Expression.Where,
Expression.Select, etc.), compile it (using LambdaExpression.Compile),
and run it. re-linq currently has no support for this, so you'll have
to code it up yourself.

Best regards,
Fabian
> https://groups.google.com/d/msg/re-motion-users/-/HbOg_lZkyvkJ.
Reply all
Reply to author
Forward
0 new messages