Build a nested lambda Expression Tree for an Entity Framework Many to Many relationship?

.net entity-framework expression-trees linq many-to-many

Question

For a project with dynamic data, I'm attempting to construct an Entity Framework 4 Many to Many relationship filter. I am aware that I must create an Expression Tree at runtime, and I have experience doing so for something as simple as a where expression like this:

private MethodCallExpression BuiltMethodCall(IQueryable _query, Type _ObjType, string _ColumnToSearch, string _SearchValue)
{
ConstantExpression value = Expression.Constant(_SearchValue);
ParameterExpression _parameter = Expression.Parameter(_ObjType, "value");
MemberExpression _property = Expression.Property(_parameter, _ColumnToSearch);
BinaryExpression comparison = Expression.Equal(_property, value);
LambdaExpression lambda = Expression.Lambda(comparison, _parameter);

//Ex: Customers.Select(c => c).Where(value => (value.City == "Seattle"))
MethodCallExpression _where = Expression.Call(typeof(Queryable), "Where", new Type[] { _query.ElementType }, new Expression[] {
    _query.Expression,
    Expression.Quote(lambda)
});
return _where;

}

These examples employ the Northwind database, which has a many-to-many join of (Customers - CustomerCustomerDemo -> CustomerDemographics), only for the sake of simplicity. When there is a nested lambda, like in the expression below, where I am obtaining all customers that have a specified customer demography, I am having difficulties generating the expression tree.

string custDemogID = "3";

//Get customers who have a particular demog
dynamic cust = context.Customers.Where(c => c.CustomerDemographics.Any(cd => cd.CustomerTypeID == custDemogID));

How can I create an expression tree with a "where" call and nested lambda for "Any"? Even if it's only some pseudo-code on how to achieve it, any assistance is welcome. There isn't much information available on this, and I need need it.

1
2
10/28/2012 9:02:59 AM

Accepted Answer

Here is the answer I came up with; Utilizing an Expression to Call a Method was the largest assistance. The major challenge was coming up with a general "Any" technique. The rest was just connecting the calls in a chain.

private MethodCallExpression BuiltMethodCall(IQueryable _query, string CustTypeID, Type _ParentObjType, Type _ChildObjType, string strChildObj, string strChildCol)
{

//This function will build a dynamic linq expression tree representing the ling calls of:
//Customers.Where(c => c.CustomerDemographics.Any(cd => cd.CustomerTypeID = custTypeID))

ConstantExpression value = Expression.Constant(CustTypeID);

//Build the outer part of the Where clause
ParameterExpression parameterOuter = Expression.Parameter(_ParentObjType, "c");
MemberExpression propertyOuter = Expression.Property(parameterOuter, strChildObj);

//Build the comparison inside of the Any clause
ParameterExpression parameterInner = Expression.Parameter(_ChildObjType, "cd");
MemberExpression propertyInner = Expression.Property(parameterInner, strChildCol);

BinaryExpression comparison = Expression.Equal(propertyInner, value);
LambdaExpression lambdaInner = Expression.Lambda(comparison, parameterInner);

//Create Generic Any Method
Func<MethodInfo, bool> methodLambda = m => m.Name == "Any" && m.GetParameters().Length == 2;
MethodInfo method = typeof(Enumerable).GetMethods().Where(methodLambda).Single().MakeGenericMethod(_ChildObjType);

//Create the Any Expression Tree and convert it to a Lambda
MethodCallExpression callAny = Expression.Call(method, propertyOuter, lambdaInner);
LambdaExpression lambdaAny = Expression.Lambda(callAny, parameterOuter);

//Build the final Where Call
MethodCallExpression whereCall = Expression.Call(typeof(Queryable), "Where", new Type[] { _query.ElementType }, new Expression[] {
    _query.Expression,
    Expression.Quote(lambdaAny)
});

return whereCall;

}

6
5/23/2017 12:30:24 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow