Reputation: 2512
How can I create the following with an expression tree?
Assume claims
is an IQueryable
of ClaimData
var lastNames = claims.Select(p1 => p1.Advisors.Select(p2 => p2.LastName));
With the example classes as follows:
public class ClaimData
{
public string name { get; set; }
public IQueryable<AdvisorData> Advisors { get; set; }
public IQueryable<ActionData> Actions { get; set; }
}
public class AdvisorData
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class ActionData
{
public string Name { get; set; }
public string Comment { get; set; }
}
Assuming we don't know which property of ClaimData (Advisors in this example) or which property of that (LastName in this example) we want to Select.
I would like to create the selector but am having difficulty. Here is code that I have attempted, but is incomplete and I am clearly getting confused
var property = typeof(ClaimData).GetProperties().Where(p =>
{
var args = p.PropertyType.GetGenericArguments();
if (args.Count() == 0) return false;
var innerProperty = args.First().GetProperties().Where(pi => PropertyByAttributeFunc(pi, table, column));
return innerProperty.Count() > 0;
}).First();
var parameterExp = Expression.Parameter(typeof(ClaimData), "p1");
var propertyExp = Expression.Property(parameterExp, property.Name);
var propertyType = property.PropertyType.GenericTypeArguments.First();
var parameterInnerExp = Expression.Parameter(propertyType, "p2");
var propertyInner = propertyType.GetProperties().Where(pi => PropertyByAttributeFunc(pi, table, column)).First();
var propertyInnerExp = Expression.Property(parameterInnerExp, propertyInner.Name);
var selectMethod = typeof(Queryable).GetMethods().Where(x => x.Name == "Select").First()
.MakeGenericMethod(property.PropertyType, typeof(string));
var genericFunc = typeof(Func<,>).MakeGenericType(property.PropertyType, typeof(string));
var genericInnerFunc = typeof(Func<,>).MakeGenericType(propertyType, typeof(string));
var innerLambda = Expression.Lambda(genericInnerFunc, propertyInnerExp, parameterInnerExp);
var expCall = Expression.Call(selectMethod, propertyExp, innerLambda);
Don't worry about this line:
var propertyInner = propertyType.GetProperties().Where(pi => PropertyByAttributeFunc(pi, table, column)).First();
It just returns the correct property for me.
Thanks
Upvotes: 0
Views: 393
Reputation: 203835
Your error was on the following line:
var selectMethod = typeof(Queryable).GetMethods()
.Where(x => x.Name == "Select").First()
.MakeGenericMethod(property.PropertyType, typeof(string));
property.PropertyType
is IQueryable<AdvisorData>
. What it should be is just AdvisorData
. The first generic argument of Select
is looking for the type of one item in the query, rather than the type of the entire IQueryable
. This means your Select
call needs to pass in an IQueryable<IQueryable<AdvisorData>>
to match the parameter Select
expects.
The change is simple enough:
var selectMethod = typeof(Queryable).GetMethods()
.Where(x => x.Name == "Select").First()
.MakeGenericMethod(property.PropertyType.GetGenericArguments()[0],
typeof(string));
Upvotes: 1