How do I implement an external expression tree?
I need to implement a query using expression syntax (because at compile time I don't know the types). For example, the request is like this:
from customer in Customers
join purchase in Purchases
on customer.ID equals purchase.CustomerID
into outerJoin
from range in outerJoin.DefaultIfEmpty()
where
customer.Name == "SomeName" &&
range.Description.Contains("SomeString") &&
customer.ID == range.CustomerID
select
new { Customer = customer, Purchase = range }
I found a way to implement group join join like this:
ITable p = _dataContext.GetTable(typeof(Purchases));
ITable c = _dataContext.GetTable(typeof(Customers));
LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(typeof(Customers), null, "ID");
LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(typeof(Purchases), null, "CustomerID");
ParameterExpression param1 = Expression.Parameter(typeof(Customers), "customer");
ParameterExpression param2 = Expression.Parameter(typeof(IEnumerable<Purchases>), "purchases");
ParameterExpression[] parameters = new ParameterExpression[] { param1, param2 };
LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, "New(customers as customers, purchases as purchases)");
MethodCallExpression joinCall =
Expression.Call(
typeof(Queryable),
"GroupJoin",
new Type[] {
typeof(Customers),
typeof(Purchases),
outerSelectorLambda.Body.Type,
resultsSelectorLambda.Body.Type
},
c.Expression,
p.Expression,
Expression.Quote(outerSelectorLambda),
Expression.Quote(innerSelectorLambda),
Expression.Quote(resultsSelectorLambda)
);
But I cannot figure out how to write the rest of the query using this syntax. Can anyone help me?
0
don
a source
to share
2 answers
I just copied + pasted the "join" implementation in dynamic.cs and made a couple of changes to get the "GroupJoin" to work.
public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values)
{
if (inner == null) throw new ArgumentNullException("inner");
if (outerSelector == null) throw new ArgumentNullException("outerSelector");
if (innerSelector == null) throw new ArgumentNullException("innerSelector");
if (resultsSelector == null) throw new ArgumentNullException("resultsSelctor");
LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(outer.ElementType, null, outerSelector, values);
LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(inner.AsQueryable().ElementType, null, innerSelector, values);
Type resultType = typeof(IEnumerable<>).MakeGenericType(inner.AsQueryable().ElementType);
ParameterExpression[] parameters = new ParameterExpression[]
{
Expression.Parameter(outer.ElementType, "outer"), Expression.Parameter(resultType, "inner")
};
LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, resultsSelector, values);
return outer.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "GroupJoin",
new Type[] { outer.ElementType, inner.AsQueryable().ElementType, outerSelectorLambda.Body.Type, resultsSelectorLambda.Body.Type },
outer.Expression, inner.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultsSelectorLambda)));
}
0
a source to share
I would follow an approach to achieve this:
-
Get the equivalent of an expression for a LINQ query.
-
Get the ToString () of the expression retrieved from a LINQ query.
-
Examine the expression to understand input parameters, type parameters, expression arguments, and more.
Come back to me if the approach mentioned is not clear.
0
a source to share