У меня есть коллекция типа IQueryable, мне нужно отсортировать ее на основе некоторых полей динамической сортировки. Поля сортировки находятся внутри списка.
Для этого я пишу следующий метод.
public List<T> Order<T>(IQueryable<T> source, List<string> propertyNames)
{
if (propertyNames != null && propertyNames.Count > 0)
{
var param = Expression.Parameter(typeof(T), string.Empty);
var property = Expression.PropertyOrField(param, propertyNames[0]);
var sort = Expression.Lambda(property, param);
MethodCallExpression orderByCall = Expression.Call(typeof(Queryable),"OrderBy",new[] { property.Type },Expression.Quote(sort));
if (propertyNames.Count > 1)
{
foreach(var item in propertyNames)
{
param = Expression.Parameter(typeof(T), string.Empty);
property = Expression.PropertyOrField(param, item);
sort = Expression.Lambda(property, param);
orderByCall = Expression.Call(
typeof(Queryable),
"ThenBy", new[] { typeof(T), property.Type },
orderByCall,
Expression.Quote(sort));
}
}
var results = (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(orderByCall);
if (results != null)
return results.ToList();
}
return null;
}
когда я выполнил MethodCallExpression orderByCall = Expression.Call(typeof(Queryable),"OrderBy",new[] { property.Type },Expression.Quote(sort));
, у меня возникло исключение
No generic method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
не связанный: if (propertyNames?.Count > 0)
Кроме того, действительно ли это должно быть сделано на IQueryable
(т.е. до того, как запрос будет отправлен в базу данных)? Если сортировку можно выполнить по списку IList (т.е. после того, как он возвращается из базы данных), это становится проще.
Извините, у меня нет прямого решения вашей ошибки.
Вот альтернативный («простой») подход к динамическому упорядочиванию ваших данных.
1) Добавьте эти методы расширения где-нибудь в свой проект
public static IOrderedQueryable<TSource> OrderBy<TSource, TProperty>(this IQueryable<TSource> source
, Expression<Func<TSource, TProperty>> expression, bool descending)
{
return !descending ? source.OrderBy(expression) : source.OrderByDescending(expression);
}
public static IOrderedQueryable<TSource> ThenBy<TSource, TProperty>(this IOrderedQueryable<TSource> source
, Expression<Func<TSource, TProperty>> expression, bool descending)
{
return !descending ? source.ThenBy(expression) : source.ThenByDescending(expression);
}
2) Теперь вы можете просто зациклить список имен свойств и применить OrderBy / ThenBy к своему IQueryable.
Другая идея: вы можете адаптировать свой метод так, чтобы он принимал выражения вместо строк с именами свойств.