LINQ order by null столбец, где порядок по возрастанию и нули должны быть последними
Я пытаюсь отсортировать список товаров по их цене.
результирующий набор должен перечислять продукты по цене от низкой до высокой по столбцу LowestPrice. Однако этот столбец может быть обнулен.
Я могу отсортировать список в порядке убывания следующим образом:
var products = from p in _context.Products
where p.ProductTypeId == 1
orderby p.LowestPrice.HasValue descending
orderby p.LowestPrice descending
select p;
// returns: 102, 101, 100, null, null
однако я не могу понять, как сортировать это в порядке возрастания.
// i'd like: 100, 101, 102, null, null
8 ответов:
Попробуйте поместить оба столбца в один и тот же порядок.
orderby p.LowestPrice.HasValue descending, p.LowestPriceв противном случае каждый orderby-это отдельная операция по переупорядочиванию коллекции каждый раз.
Это должно упорядочить те, с A со значением сначала," затем " порядок значения.
это действительно помогает понять синтаксис запроса LINQ и как он переводится на вызовы метода LINQ.
получается, что
var products = from p in _context.Products where p.ProductTypeId == 1 orderby p.LowestPrice.HasValue descending orderby p.LowestPrice descending select p;будет переведен компилятором в
var products = _context.Products .Where(p => p.ProductTypeId == 1) .OrderByDescending(p => p.LowestPrice.HasValue) .OrderByDescending(p => p.LowestPrice) .Select(p => p);это, безусловно, не то, что вы хотите. Это сортирует по
Product.LowestPrice.HasValueнаdescendingзаказать, а затем повторно сортирует всю коллекцию поProduct.LowestPriceнаdescendingпорядок.то, что вы хотите, это
var products = _context.Products .Where(p => p.ProductTypeId == 1) .OrderByDescending(p => p.LowestPrice.HasValue) .ThenBy(p => p.LowestPrice) .Select(p => p);который можно получить с помощью синтаксиса запроса на
var products = from p in _context.Products where p.ProductTypeId == 1 orderby p.LowestPrice.HasValue descending, p.LowestPrice select p;подробные сведения о переводах из синтаксиса запросов в вызовы методов см. В спецификации языка. Серьезно. Прочитать его.
У меня есть другой вариант в этой ситуации. Мой список objList, и я должен заказать, но нули должны быть в конце. мое решение:
var newList = objList.Where(m=>m.Column != null) .OrderBy(m => m.Column) .Concat(objList.where(m=>m.Column == null));
решение для строковых значений действительно странно:
.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString)единственная причина, которая работает, потому что первое выражение,
OrderBy()вродеboolзначения:true/false.falseрезультат идти первым послеtrueрезультат (nullables) иThenBy()сортировка ненулевых значений в алфавитном порядке.Итак, я предпочитаю делать что-то более читаемое, например:
.OrderBy(f => f.SomeString ?? "z")если
SomeStringравно null, он будет заменен на"z"и затем сортировать все в алфавитном порядке.Примечание: это не окончательное решение, так как
"z"идет первым, чем z-значения, такие какzebra.обновление 9/6/2016-о комментарии @jornhd, это действительно хорошее решение, но оно все еще немного сложное, поэтому я рекомендую обернуть его в класс расширения, например:
public static class MyExtensions { public static IOrderedEnumerable<T> NullableOrderBy<T>(this IEnumerable<T> list, Func<T, string> keySelector) { return list.OrderBy(v => keySelector(v) != null ? 0 : 1).ThenBy(keySelector); } }и просто использовать его как:
var sortedList = list.NullableOrderBy(f => f.SomeString);
это то, что я придумал, потому что я использую методы расширения, а также мой элемент является строкой, поэтому нет
.HasValue:.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString)это работает с объектами LINQ 2 в памяти. Я не тестировал его с помощью EF или любого DB ORM.
Я пытался найти решение LINQ для этого, но не получается из ответов здесь.
мой окончательный ответ был:
.OrderByDescending(p.LowestPrice.HasValue).ThenBy(p.LowestPrice)
ниже есть метод расширения, чтобы проверить на null, если вы хотите отсортировать на собственность ребенка в качестве параметра keyselector.
public static IOrderedEnumerable<T> NullableOrderBy<T>(this IEnumerable<T> list, Func<T, object> parentKeySelector, Func<T, object> childKeySelector) { return list.OrderBy(v => parentKeySelector(v) != null ? 0 : 1).ThenBy(childKeySelector); }и просто использовать его как:
var sortedList = list.NullableOrderBy(x => x.someObject, y => y.someObject?.someProperty);