问题
How can I dynamically build an order-by expression when only knowing the name of the property (or even the name of a sub-property)?
What I'm trying to achieve is something like:
dbResult = // some database-query as IQueryable<TSource> which is not yet executed;
if (!string.IsNullOrEmpty(request.OrderBy)) { // the user want's to group the results
var grouped = dbResult.GroupBy(/* this should be build dynamically */);
}
I need something to start with as GroupBy is awaiting a Func<TSource, TKey> but I only know TKey at runtime which can be string, int or even a Guid.
The user could pass something like "Country.Name" to the request.OrderBy property which means the results should be grouped by a sub-property (sub-select), the name of a country.
I think ExpressionTrees is the way to go here but I'm stuck before even getting started as I don't know how to handle the unknown Type as well as the option to group by a property of a sub-select/sub-property.
回答1:
Here is how you can build dynamically a GroupBy expression/query:
public static class QueryableExtensions
{
public static IQueryable GroupByMember(this IQueryable source, string memberPath)
{
var parameter = Expression.Parameter(source.ElementType, "x");
var member = memberPath.Split('.')
.Aggregate((Expression)parameter, Expression.PropertyOrField);
var selector = Expression.Lambda(member, parameter);
var groupByCall = Expression.Call(typeof(Queryable), "GroupBy",
new Type[] { parameter.Type, member.Type },
source.Expression, Expression.Quote(selector));
return source.Provider.CreateQuery(groupByCall);
}
}
The problem is though that there is no good generic way of representing the result. And working with non generic IQueryable / IEnumerable is not easy because almost all LINQ methods operate on generic interfaces. Especially with IQueryable you'll find that you need creating more and more methods like this, so you might consider using Dynamic LINQ package.
来源:https://stackoverflow.com/questions/40246515/building-orderby-expression-at-runtime-by-property-name-which-can-be-nested