问题
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