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);