我正在尝试对我的源进行分页,但在我的情况下,我无法将GetPropertyValue
的结果放在变量中,因为我需要x
来执行此操作:
public IEnumerable<TModel> Paginate(IQueryable<TModel> source, ref int totalPages, int pageIndex, int pageSize, string sortfield, SortDirection? sortdir)
{
totalPages = (int)Math.Ceiling(source.Count() / (double)pageSize);
if (sortdir == SortDirection.Descending)
{
return source.OrderByDescending(x => GetPropertyValue(x, sortfield)).Skip(pageIndex * pageSize).Take(pageSize).ToList();
}
else
{
return source.OrderBy(x => GetPropertyValue(x, sortfield)).Skip(pageIndex * pageSize).Take(pageSize).ToList();
}
}
private static object GetPropertyValue(object obj, string name)
{
return obj == null ? null : obj.GetType().GetProperty(name).GetValue(obj, null);
}
在这种情况下,我该怎么办?
答案 0 :(得分:9)
Lambda表达式(那些在Where,OrderBy等中使用)不能包含任何C#特定代码,它们只能包含表达式树,它被转换为SQL。你不能在那里调用任何任意方法,除了EF文档中提到的方法,如SqlFunctions等。
为了在运行时使用字段名进行排序,您必须在运行时创建一个lambda表达式并将其传递。
public IEnumerable<TModel> Paginate(IQueryable<TModel> source, ref int totalPages, int pageIndex, int pageSize, string sortfield, SortDirection? sortdir)
{
totalPages = (int)Math.Ceiling(source.Count() / (double)pageSize);
if (sortdir == SortDirection.Descending)
{
return source.OrderByDescending(sortfield).Skip(pageIndex * pageSize).Take(pageSize).ToList();
}
else
{
return source.OrderBy(sortfield).Skip(pageIndex * pageSize).Take(pageSize).ToList();
}
}
public static class QueryableHelper
{
public static IQueryable<TModel> OrderBy<TModel>(this IQueryable<TModel> q, string name)
{
Type entityType = typeof(TModel);
PropertyInfo p = entityType.GetProperty(name);
MethodInfo m = typeof(QueryableHelper).GetMethod("OrderByProperty").MakeGenericMethod(entityType, p.PropertyType);
return(IQueryable<TModel>) m.Invoke(null, new object[] { q, p });
}
public static IQueryable<TModel> OrderByDescending<TModel>(this IQueryable<TModel> q, string name)
{
Type entityType = typeof(TModel);
PropertyInfo p = entityType.GetProperty(name);
MethodInfo m = typeof(QueryableHelper).GetMethod("OrderByPropertyDescending").MakeGenericMethod(entityType, p.PropertyType);
return (IQueryable<TModel>)m.Invoke(null, new object[] { q, p });
}
public static IQueryable<TModel> OrderByPropertyDescending<TModel, TRet>(IQueryable<TModel> q, PropertyInfo p)
{
ParameterExpression pe = Expression.Parameter(typeof(TModel));
Expression se = Expression.Convert(Expression.Property(pe, p), typeof(object));
return q.OrderByDescending(Expression.Lambda<Func<TModel, TRet>>(se, pe));
}
public static IQueryable<TModel> OrderByProperty<TModel, TRet>(IQueryable<TModel> q, PropertyInfo p)
{
ParameterExpression pe = Expression.Parameter(typeof(TModel));
Expression se = Expression.Convert(Expression.Property(pe, p), typeof(object));
return q.OrderBy(Expression.Lambda<Func<TModel, TRet>>(se, pe));
}
}
此解决方案仅适用于单一级别的属性,但如果您希望嵌套级别比需要更多工作,可能您可以查看以下SDK来完成所有这些操作。
但是,如果你看一下Entity REST SDK本身,它有许多东西和你可能需要的所有东西。免责声明:我是作者。
答案 1 :(得分:1)
您应该动态创建Expression<Func<TSource, TOrder>>
并将其传递给OrderBy
,而不是使用反射。
查看here以了解如何创建动态查询。