Я нашел пример в Примеры VS2008 для Dynamic LINQ, который позволяет использовать строку в стиле sql (например, OrderBy("Name, Age DESC")) для заказа. К сожалению, включенный метод работает только на IQueryable<T>. Есть ли способ получить эту функциональность на IEnumerable<T>?





Я предполагаю, что было бы сработать использовать отражение, чтобы получить любое свойство, которое вы хотите отсортировать:
IEnumerable<T> myEnumerables
var query=from enumerable in myenumerables
where some criteria
orderby GetPropertyValue(enumerable,"SomeProperty")
select enumerable
private static object GetPropertyValue(object obj, string property)
{
System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
return propertyInfo.GetValue(obj, null);
}
Обратите внимание, что использование отражения значительно медленнее, чем прямой доступ к свойству, поэтому производительность необходимо будет исследовать.
это вообще работает? orderby не требуется значение, а селектор lamba / delegate (Func <TSource, TKey> keySelector) ..
Я попробовал этот пример перед тем, как опубликовать его, и да, он работает.
+1 Это именно то, что я искал! Это отлично подходит для простых задач сортировки страниц.
У меня это не сработало. Я что-то пропустил? Какой должна быть SomeProperty. Я попытался указать имя свойства, а также property.GetType (). У меня IQueryable <>, а не IEnumerable <>
Метод GetPropertyValue будет выполняться для всех элементов, это плохое решение.
@Alex Shkor: Как вы должны сортировать элементы, не глядя на все элементы? Однако в других ответах есть лучшие решения.
Вы можете добавить это:
public static IEnumerable<T> OrderBy( this IEnumerable<T> input, string queryString) {
//parse the string into property names
//Use reflection to get and sort by properties
//something like
foreach( string propname in queryString.Split(','))
input.OrderBy( x => GetPropertyValue( x, propname ) );
// I used Kjetil Watnedal's reflection example
}
Функция GetPropertyValue взята из Ответ Кьетила Ватнедала
Вопрос в том, почему? Любая такая сортировка вызовет исключения во время выполнения, а не во время компиляции (например, ответ D2VIANT).
Если вы имеете дело с Linq to Sql и orderby является деревом выражений, он все равно будет преобразован в SQL для выполнения.
Метод GetPropertyValue будет выполняться для всех элементов, это плохое решение.
OrderBy не поддерживает предыдущий порядок !!
Только что наткнулся на эту старичку ...
Чтобы сделать это без динамической библиотеки LINQ, вам просто понадобится код, как показано ниже. Это охватывает наиболее распространенные сценарии, включая вложенные свойства.
Чтобы заставить его работать с IEnumerable<T>, вы можете добавить несколько методов-оболочек, которые проходят через AsQueryable, но приведенный ниже код является необходимой базовой логикой Expression.
public static IOrderedQueryable<T> OrderBy<T>(
this IQueryable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(
this IQueryable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(
this IOrderedQueryable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(
this IOrderedQueryable<T> source,
string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
static IOrderedQueryable<T> ApplyOrder<T>(
IQueryable<T> source,
string property,
string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach(string prop in props) {
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] {source, lambda});
return (IOrderedQueryable<T>)result;
}
Обновлено: становится веселее, если вы хотите смешать это с dynamic - хотя обратите внимание, что dynamic применяется только к LINQ-to-Objects (деревья выражений для ORM и т. д. Не могут действительно представлять запросы dynamic - MemberExpression не поддерживает его). Но вот способ сделать это с помощью LINQ-to-Objects. Обратите внимание, что выбор Hashtable обусловлен благоприятной семантикой блокировки:
using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Runtime.CompilerServices;
static class Program
{
private static class AccessorCache
{
private static readonly Hashtable accessors = new Hashtable();
private static readonly Hashtable callSites = new Hashtable();
private static CallSite<Func<CallSite, object, object>> GetCallSiteLocked(
string name)
{
var callSite = (CallSite<Func<CallSite, object, object>>)callSites[name];
if (callSite == null)
{
callSites[name] = callSite = CallSite<Func<CallSite, object, object>>
.Create(Binder.GetMember(
CSharpBinderFlags.None,
name,
typeof(AccessorCache),
new CSharpArgumentInfo[] {
CSharpArgumentInfo.Create(
CSharpArgumentInfoFlags.None,
null)
}));
}
return callSite;
}
internal static Func<dynamic,object> GetAccessor(string name)
{
Func<dynamic, object> accessor = (Func<dynamic, object>)accessors[name];
if (accessor == null)
{
lock (accessors )
{
accessor = (Func<dynamic, object>)accessors[name];
if (accessor == null)
{
if (name.IndexOf('.') >= 0) {
string[] props = name.Split('.');
CallSite<Func<CallSite, object, object>>[] arr
= Array.ConvertAll(props, GetCallSiteLocked);
accessor = target =>
{
object val = (object)target;
for (int i = 0; i < arr.Length; i++)
{
var cs = arr[i];
val = cs.Target(cs, val);
}
return val;
};
} else {
var callSite = GetCallSiteLocked(name);
accessor = target =>
{
return callSite.Target(callSite, (object)target);
};
}
accessors[name] = accessor;
}
}
}
return accessor;
}
}
public static IOrderedEnumerable<dynamic> OrderBy(
this IEnumerable<dynamic> source,
string property)
{
return Enumerable.OrderBy<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> OrderByDescending(
this IEnumerable<dynamic> source,
string property)
{
return Enumerable.OrderByDescending<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenBy(
this IOrderedEnumerable<dynamic> source,
string property)
{
return Enumerable.ThenBy<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenByDescending(
this IOrderedEnumerable<dynamic> source,
string property)
{
return Enumerable.ThenByDescending<dynamic, object>(
source,
AccessorCache.GetAccessor(property),
Comparer<object>.Default);
}
static void Main()
{
dynamic a = new ExpandoObject(),
b = new ExpandoObject(),
c = new ExpandoObject();
a.X = "abc";
b.X = "ghi";
c.X = "def";
dynamic[] data = new[] {
new { Y = a },
new { Y = b },
new { Y = c }
};
var ordered = data.OrderByDescending("Y.X").ToArray();
foreach (var obj in ordered)
{
Console.WriteLine(obj.Y.X);
}
}
}
Лучший чертов код, который я видел :) Просто решил миллион проблем в моем проекте :)
Марк, у вас есть подобное расширение для LIKE Condition?
@Prasad - LIKE немного отличается, но какой сервер? Для LINQ-to-SQL есть SqlMethods.Like: msdn.microsoft.com/en-us/library/…; Вы можете добавить больше информации о том, что ищете?
Я использую SQL как бэкэнд, мне нужно выполнить операцию поиска с именами динамических параметров, как в вашем расширении OrderBy.
Что ж, вы, безусловно, можете использовать SqlMethods.Like в собственном выражении; действительно непонятно где ломается ... можете уточнить? Может задать вопрос?
Спасибо, Марк, вчера делал в stackoverflow.com/questions/1654745/dynamic-linq-like. Лучше, если у меня будет образец
Похоже, многие люди добились успеха с этим кодом - хоть убей, я не могу придумать, как его применить! Это методы расширения, верно? Как их использовать ??
@Dave - вам нужно начать с IQueryable<T>, поэтому, если у вас есть что-то вроде List<T> (то есть IEnumerable<T>), вам может потребоваться использовать AsQueryable() - например, var sorted = someList.AsQueryable().OrderBy("Foo.Bar");
Вы видели это ... это может помочь некоторым людям ... stackoverflow.com/questions/557819/… это более строго типизированное решение.
Отличный код! Знаете ли вы, как добавить поддержку метода расширения «Count ()»? Вызов метода расширения - это тихая боль, и у меня проблемы с построением выражения с их помощью. Я пытаюсь добавить поддержку «Count ()» для IQueryable <T>, которая кодируется как расширение в типе «Queryable».
@ile - var ordered = someData.OrderBy("Name"); - или для данных IEnumerable<T>, var ordered = someData.AsQueryable().OrderBy("Name");
Это можно сделать уже с AsQueryAble (). OrderBy (). ThenBy (). Я что-то упускаю. Редактировать Я только что заметил, что вышеуказанные методы возвращают IOrderedQueryable, а перечисленные мной методы возвращают IOrderedEnumerable.
если использовать переключатель, который будет быстрее. отражение против переключателя
@ Нарио - контекст? включить отражение Какие, vs Какие? О, вы имеете в виду наращивание с помощью .OrderBy(x => x.Something) (умноженное на 10 или что-то еще) - скорее всего, switch
переключатель (название свойства) {case "property1": result = datacontex.orderby (x => x.property1) break; case "property2": result = datacontex.orderby (x => x.property2) break; }
Спасибо за это! Я обнаружил одно улучшение: вместо оператора Reflection GetMethod () .. Invoke () вы можете построить результат непосредственно в linq: var expression = Expression.Call (typeof (Queryable), methodName, new [] {source. ElementType, expr.Type}, source.Expression, lambda); var result = source.Provider.CreateQuery <T> (выражение);
Можно ли использовать этот подход с объектом, реализующим IDynamicMetaObjectProvider? У меня проблемы, описанные в этом посте: stackoverflow.com/questions/11206631/…
@BonyT нет, но я добавил "динамический" подход к вашему вопросу
@MarcGravell: Я публикую вопрос по этому адресу: stackoverflow.com/questions/12495873/dynamic-sort-in-linq/…. и проблема в том, что когда я использую ваши методы расширения, результат не сортируется. в чем проблема?
Большое спасибо за этот код. Тот же вопрос, что и Моисей: знаете ли вы, как добавить поддержку метода расширения «Count ()»?
Есть ли способ применить сортировку по вложенной коллекции?
@ahmed зависит ... Что это за иметь в виду?
Если кому-то интересно, я заставил его работать с IEnumerable, просто заменив lambda на lambda.Compile() в предпоследней строке, исключив очевидные замены IQueryable> IEnumerable и IOrderedQueryable на IOrderedEnumerable. Обертки не задействованы
Вау, это смешно - пара строк кода увеличена до сорока, чтобы избежать использования System.Linq.Dynamic? Есть ли какое-то преимущество в том, чтобы не использовать его? Взгляните на ответ @Alaa Osta ниже (собственно решение исходного вопроса).
@MGOwen, вы, кажется, неправильно понимаете природу кода. 40 строк одинаковы, независимо от того, 40 строк ли вы помещаете где-то в своем проекте, или эти строки поступают (предварительно скомпилированные или как исходные) во внешней библиотеке. Это было бы довольно удивительно, если бы я связался в октябре 2008 года с библиотекой на nuget, которая существовала с декабря 2011 года (не в последнюю очередь потому, что nuget тогда тоже не существовал), но фундаментальным «что он делает» является одно и тоже. Кроме того, вы используете фразу «фактическое решение», как будто существует некий четко определенный согласованный единственный путь к каждому вопросу кодирования: его нет.
@MGOwen, кстати, внешняя библиотека - это 2296 строк кода (не включая AssemblyInfo.cs); из-за чего 40 строк здесь выглядят довольно разумно
@MarcGravell Аххх Хорошо, извини, не заметил, что этот ответ был таким старым. Я был очень сбит с толку, как и 99% людей, которые зададут этот вопрос. Мой комментарий был адресован не вам, а им: сотням людей, которые задают этот вопрос и нуждаются в наилучшем доступном на данный момент ответе. WRT строки кода, я думаю, что большинство программистов предпочтут использовать установленную библиотеку для решения проблемы, и если я правильно понимаю связывание, в любом случае будет включен только используемый код, верно?
@MGOwen .net не использует компоновщик (за исключением некоторых фреймворков AOT). Будет включен весь IL, но только те методы, которые используются, будут JIT-ed
Хорошо, только не переименовывайте никакие свойства.
@MarcGravell выполняет эту сортировку до или после запуска sql? Я также использую разбиение на страницы, чтобы получить только несколько записей за раз, но для получения правильных записей сортировка должна выполняться в операторе sql, а не в памяти.
@Zaphod до тех пор, пока входной сигнал является подходящим IQueryable<T>, он включается в запрос без выполнения каких-либо действий в памяти.
Очень хороший код, он мне очень помог с сортировкой по имени столбца, хранящемуся в строке. Однако с интерфейсами это работает не очень хорошо. Я имею в виду, что если у вас есть IQueryable класса интерфейса и вы попытаетесь выполнить заказ по столбцу, который не является частью интерфейса, вы получите сообщение об ошибке. К счастью, это достаточно легко исправить. Замена всех экземпляров typeof (T) на source.ElementType позволит упорядочить по любому столбцу фактического класса, который обрабатывается в запросе.
@MarcGravell, в первом фрагменте вам не нужно вычислять самостоятельно delegateType LambdaExpression. Если вы не передаете его в качестве первого аргумента, он автоматически вычисляется Expression.Lambda.
Очень хорошо ... В моем очень простом тесте это выполняется за 29 мс против 148 мс System.Linq.Dynamic.
Я не могу понять ни одной строчки из этого кода, но он работает!
Я использую первую часть кода, и она работает очень здорово. Но после изменения проекта на .net Core 3.0 предупреждения, допускающие значение NULL, сводят меня с ума. Не могли бы вы обновить код?
@Henning (приставляет язык к щеке) - конечно! #nullable disable
@MarcGravell Привет, мастер, мне нужно избегать ввода, чтобы предотвратить инъекции?
@Nicholas no, слой парсера дерева выражений / генератора SQL имеет дело с этим, как с параметрами
Я наткнулся на этот вопрос, ища несколько предложений Linq orderby и, возможно, это было то, что искал автор
Вот как это сделать:
var query = pets.OrderBy(pet => pet.Name).ThenByDescending(pet => pet.Age);
+1 отменил голосование против из-за отсутствия объяснений. Я также думаю, что автора могли заинтересовать несколько заказов. Даже если динамическое был ключевое слово, нет причин голосовать против.
Альтернативное решение использует следующий класс / интерфейс. Это не совсем динамично, но работает.
public interface IID
{
int ID
{
get; set;
}
}
public static class Utils
{
public static int GetID<T>(ObjectQuery<T> items) where T:EntityObject, IID
{
if (items.Count() == 0) return 1;
return items.OrderByDescending(u => u.ID).FirstOrDefault().ID + 1;
}
}
Просто опираясь на то, что сказали другие. Я обнаружил, что следующее работает довольно хорошо.
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> input, string queryString)
{
if (string.IsNullOrEmpty(queryString))
return input;
int i = 0;
foreach (string propname in queryString.Split(','))
{
var subContent = propname.Split('|');
if (Convert.ToInt32(subContent[1].Trim()) == 0)
{
if (i == 0)
input = input.OrderBy(x => GetPropertyValue(x, subContent[0].Trim()));
else
input = ((IOrderedEnumerable<T>)input).ThenBy(x => GetPropertyValue(x, subContent[0].Trim()));
}
else
{
if (i == 0)
input = input.OrderByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
else
input = ((IOrderedEnumerable<T>)input).ThenByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
}
i++;
}
return input;
}
Я пытался сделать это, но у меня возникли проблемы с Решение Кьетила Ватнедала, потому что я не использую встроенный синтаксис linq - я предпочитаю синтаксис в стиле метода. Моя конкретная проблема заключалась в попытке выполнить динамическую сортировку с использованием настраиваемого IComparer.
Мое решение закончилось так:
Учитывая такой запрос IQueryable:
List<DATA__Security__Team> teams = TeamManager.GetTeams();
var query = teams.Where(team => team.ID < 10).AsQueryable();
И учитывая аргумент поля сортировки во время выполнения:
string SortField; // Set at run-time to "Name"
Динамический OrderBy выглядит так:
query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField));
И это с помощью небольшого вспомогательного метода GetReflectedPropertyValue ():
public static string GetReflectedPropertyValue(this object subject, string field)
{
object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
return reflectedValue != null ? reflectedValue.ToString() : "";
}
И последнее - я упомянул, что хотел, чтобы OrderBy использовал собственный IComparer, потому что я хотел использовать Естественная сортировка.
Для этого я просто изменяю OrderBy на:
query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField), new NaturalSortComparer<string>());
См. Код для NaturalSortComparer() в эта почта.
Вот еще кое-что, что я нашел интересным. Если вашим источником является DataTable, вы можете использовать динамическую сортировку без использования Dynamic Linq.
DataTable orders = dataSet.Tables["SalesOrderHeader"];
EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
orderby order.Field<DateTime>("OrderDate")
select order;
DataView view = query.AsDataView();
bindingSource1.DataSource = view;
ссылка: http://msdn.microsoft.com/en-us/library/bb669083.aspx (с использованием DataSetExtensions)
Вот еще один способ сделать это, преобразовав его в DataView:
DataTable contacts = dataSet.Tables["Contact"];
DataView view = contacts.AsDataView();
view.Sort = "LastName desc, FirstName asc";
bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Просто наткнулся на этот вопрос.
Используя реализацию Марка ApplyOrder, описанную выше, я собрал метод Extension, который обрабатывает SQL-подобные строки, например:
list.OrderBy("MyProperty DESC, MyOtherProperty ASC");
Подробности можно найти здесь: http://aonnull.blogspot.com/2010/08/dynamic-sql-like-linq-orderby-extension.html
Отличный материал, просто добавьте следующую модификацию, чтобы сделать имя свойства нечувствительным к регистру: PropertyInfo pi = type.GetProperty (prop, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
Слишком просто без каких-либо осложнений:
using System.Linq.Dynamic; вверху.vehicles = vehicles.AsQueryable().OrderBy("Make ASC, Year DESC").ToList();а где ты System.Linq.Dynamic взял?
Работает также при использовании linq с MongoDB.
Принятый ответ, возможно, был правильным ответом в 2008 году, но в настоящее время это самый простой и самый правильный ответ.
Это действительно хорошее и простое управление, такая большая внутренняя сложность, понравилось
Можно ли сортировать по вложенному свойству?, Например: cars = cars.AsQueryable (). OrderBy ("Status.Label ASC, Year DESC"). ToList ();
Я подумал, что принятый ответ был потрясающим, но это чистое золото!
Для людей в «будущем», если вы используете ядро dotnet, используйте это: nuget.org/packages/System.Linq.Dynamic.Core
Для всех, кто просматривает это, как и я для того же решения - это работает для сортировки «вложенных» объектов, то есть vehicles.AsQueryable().OrderBy("Tire.Size").ToList();, где Tire - это объект, принадлежащий Vehicle.
@RafaelMerlin Также пространство имен теперь System.Linq.Dynamic.Core
nuget.org/packages/System.Linq.Dynamic.Core - это бесплатная или лицензионная версия?
Благодаря Маартену (Запросить коллекцию с помощью объекта PropertyInfo в LINQ) я получил такое решение:
myList.OrderByDescending(x => myPropertyInfo.GetValue(x, null)).ToList();
В моем случае я работал над «ColumnHeaderMouseClick» (WindowsForm), поэтому просто нашел конкретный нажатый столбец и соответствующий ему PropertyInfo:
foreach (PropertyInfo column in (new Process()).GetType().GetProperties())
{
if (column.Name == dgvProcessList.Columns[e.ColumnIndex].Name)
{}
}
ИЛИ ЖЕ
PropertyInfo column = (new Process()).GetType().GetProperties().Where(x => x.Name == dgvProcessList.Columns[e.ColumnIndex].Name).First();
(убедитесь, что имена ваших столбцов соответствуют свойствам объекта)
Ваше здоровье
После долгих поисков это сработало для меня:
public static IEnumerable<TEntity> OrderBy<TEntity>(this IEnumerable<TEntity> source,
string orderByProperty, bool desc)
{
string command = desc ? "OrderByDescending" : "OrderBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command,
new[] { type, property.PropertyType },
source.AsQueryable().Expression,
Expression.Quote(orderByExpression));
return source.AsQueryable().Provider.CreateQuery<TEntity>(resultExpression);
}
Преобразуйте List в IEnumerable или Iquerable, добавьте, используя пространство имен System.LINQ.Dynamic, затем вы можете указать имена свойств в строке, разделенной запятыми, в метод OrderBy, который по умолчанию поступает из System.LINQ.Dynamic.
Вы можете преобразовать IEnumerable в IQueryable.
items = items.AsQueryable().OrderBy("Name ASC");
var result1 = lst.OrderBy(a=>a.Name);// for ascending order.
var result1 = lst.OrderByDescending(a=>a.Name);// for desc order.
Этот ответ является ответом на комментарии, в которых нужен пример решения, предоставленного @John Sheehan - Runscope.
Please provide an example for the rest of us.
в DAL (уровень доступа к данным),
Версия IEnumerable:
public IEnumerable<Order> GetOrders()
{
// i use Dapper to return IEnumerable<T> using Query<T>
//.. do stuff
return orders // IEnumerable<Order>
}
Версия IQueryable
public IQueryable<Order> GetOrdersAsQuerable()
{
IEnumerable<Order> qry= GetOrders();
//use the built-in extension method AsQueryable in System.Linq namespace
return qry.AsQueryable();
}
Теперь вы можете использовать версию IQueryable для привязки, например, GridView в Asp.net и получить преимущества для сортировки (вы не можете сортировать с помощью версии IEnumerable)
Я использовал Dapper в качестве ORM и создал версию IQueryable, а также с легкостью использовал сортировку в GridView в asp.net.
Сначала установите динамический Инструменты -> Диспетчер пакетов NuGet -> Консоль диспетчера пакетов
install-package System.Linq.Dynamic
Добавить Пространство именusing System.Linq.Dynamic;
Теперь вы можете использовать OrderBy("Name, Age DESC")
Как я могу использовать его с внутренней сортировкой свойств - например, OrderBy ("Branch.BranchName", "Descending")
У меня это работает. Возможно, потому, что этому вопросу 10 лет, а этот более простой метод появился позже.
Используйте динамический linq
просто добавьте using System.Linq.Dynamic;
И используйте его так, чтобы упорядочить все свои столбцы:
string sortTypeStr = "ASC"; // or DESC
string SortColumnName = "Age"; // Your column name
query = query.OrderBy($"{SortColumnName} {sortTypeStr}");
Вы можете использовать это:
public List<Book> Books(string orderField, bool desc, int skip, int take)
{
var propertyInfo = typeof(Book).GetProperty(orderField);
return _context.Books
.Where(...)
.OrderBy(p => !desc ? propertyInfo.GetValue(p, null) : 0)
.ThenByDescending(p => desc ? propertyInfo.GetValue(p, null) : 0)
.Skip(skip)
.Take(take)
.ToList();
}
Пару лет спустя я натыкаюсь на это; это сработало для меня, как во сне. У меня есть динамическая сортировка от 1 до 3 свойств, и это работает как мечта. Легко внедрить и без проблем.
Мне нравится этот ответ, но как я могу заставить эту работу, если мне нужно отсортировать по свойству дочернего класса?
вы можете сделать это для нескольких заказов
IOrderedEnumerable<JToken> sort;
if (query.OrderBys[0].IsDESC)
{
sort = jarry.OrderByDescending(r => (string)r[query.OrderBys[0].Key]);
}
else
{
sort = jarry.OrderBy(r =>
(string) r[query.OrderBys[0].Key]);
}
foreach (var item in query.OrderBys.Skip(1))
{
if (item.IsDESC)
{
sort = sort.ThenByDescending(r => (string)r[item.Key]);
}
else
{
sort = sort.ThenBy(r => (string)r[item.Key]);
}
}
На мой взгляд, лучший ответ на эту дату: библиотека System.Linq.Dynamic.Core.