Using 反射 /questions/tagged/reflection and 表达式树 /questions/tagged/expression-trees您可以提供参数,然后调用OrderBy
函数,而不是返回Expression<Func<Task, T>>
然后打电话OrderBy
.
注意OrderBy
是一种扩展方法,并且已在两者中实现System.Linq.Enumarable
and System.Linq.Queryable
类。第一个是为了链接到对象 /questions/tagged/linq-to-objects后者是为了实体链接 /questions/tagged/linq-to-entities. 实体框架 /questions/tagged/entity-framework需要查询的表达式树才能将其转换为 SQL 命令。所以我们使用Queryable
执行。
可以通过扩展方法来完成(解释作为注释添加):
public static IOrderedQueryable<TSource> OrderBy<TSource>(
this IQueryable<TSource> query, string propertyName)
{
var entityType = typeof(TSource);
//Create x=>x.PropName
var propertyInfo = entityType.GetProperty(propertyName);
ParameterExpression arg = Expression.Parameter(entityType, "x");
MemberExpression property = Expression.Property(arg, propertyName);
var selector = Expression.Lambda(property, new ParameterExpression[] { arg });
//Get System.Linq.Queryable.OrderBy() method.
var enumarableType = typeof(System.Linq.Queryable);
var method = enumarableType.GetMethods()
.Where(m => m.Name == "OrderBy" && m.IsGenericMethodDefinition)
.Where(m =>
{
var parameters = m.GetParameters().ToList();
//Put more restriction here to ensure selecting the right overload
return parameters.Count == 2;//overload that has 2 parameters
}).Single();
//The linq's OrderBy<TSource, TKey> has two generic types, which provided here
MethodInfo genericMethod = method
.MakeGenericMethod(entityType, propertyInfo.PropertyType);
/*Call query.OrderBy(selector), with query and selector: x=> x.PropName
Note that we pass the selector as Expression to the method and we don't compile it.
By doing so EF can extract "order by" columns and generate SQL for it.*/
var newQuery = (IOrderedQueryable<TSource>)genericMethod
.Invoke(genericMethod, new object[] { query, selector });
return newQuery;
}
现在你可以称这个重载为OrderBy
就像它的任何其他过载一样。
例如:
var cheapestItems = _context.Items.OrderBy("Money").Take(10).ToList();
翻译过来就是:
SELECT TOP (10) {coulmn names} FROM [dbo].[Items] AS [Extent1]
ORDER BY [Extent1].[Money] ASC
这种方法可用于定义所有重载OrderBy
and OrderByDescending
方法有string
属性选择器。