I want to generate expression trees using the API for the following:
var managers = dataContext.Employees.Where(e => e.Subordinates.Any());
Additionally, how do I then generate the expression tree to do this:
var managedEmployees = managers.ToDictionary(key => key.Manager, value => value.Subordinates.Select(s => s.FullName));
I've come up with the following so far for the .Where(), but it errors because it doesn't like the type parameters in new Type[] { typeof(Func<Employee, IEnumerable<Employee>>) }
.
ParameterExpression employeesParameter = Expression.Parameter(typeof(Employee), "e");
MemberExpression subordinatesProperty = Expression.Property(employeesParameter, typeof(Employee).GetProperty("Subordinates"));
MethodCallExpression hasSubordinates = Expression.Call(typeof(Enumerable),
"Any",
new Type[] { typeof(Employee) },
subordinatesProperty);
LambdaExpression whereLambda = Expression.Lambda(hasSubordinates, employeesParameter);
MethodCallExpression whereExpression = Expression.Call(typeof(Queryable),
"Where",
new Type[] { typeof(Func<Employee, IEnumerable<Employee>>) },
dataContext.Employees.AsQueryable(),
whereLambda);
I got this. The type parameters on Any
and Where
need to be Employee
, not IQueryable<Employee>
or IEnumerable<Employee>
because it's just looking for the type parameters, not the actual types. I believe you also need an Expression.Constant(dataContext.Employees)
instead of straight dataContext.Employees
.
ParameterExpression employeesParameter = Expression.Parameter(typeof(Employee), "e");
MemberExpression subordinatesProperty = Expression.Property(employeesParameter, typeof(Employee).GetProperty("Subordinates"));
MethodCallExpression hasSubordinates = Expression.Call(typeof(Enumerable),
"Any",
new Type[] { typeof(Employee) },
subordinatesProperty);
LambdaExpression whereLambda = Expression.Lambda(hasSubordinates, employeesParameter);
MethodCallExpression whereExpression = Expression.Call(typeof(Queryable),
"Where",
new Type[] { typeof(Employee) },
Expression.Constant(dataContext.Employees),
whereLambda);
To call Any
for your MemberExpression
you should do this
ParameterExpression employeesParameter = Expression.Parameter(typeof(Employee), "e");
MemberExpression subordinatesProperty = Expression.Property(employeesParameter, typeof(Employee).GetProperty("Subordinates"));
var mi = typeof(Enumerable).GetMethods().First(x => x.Name == "Any" && x.GetParameters().Length == 1);
mi = mi.MakeGenericMethod(typeof (bool));
var hasSubordinates = Expression.Call(mi, subordinatesProperty);
and Where
var lambda = Expression.Lambda<Func<Employee, bool>>(hasSubordinates, employeesParameter);
var res = i.Where(lambda.Compile());