LINQ order by null column où l'ordre est ascendant et les valeurs NULL doivent être les dernières
J'essaie de trier une liste de produits par leur prix.
Le jeu de résultats doit lister les produits par prix de bas en haut par la colonne LowestPrice
. Cependant, cette colonne est nullable.
Je peux trier la liste Par Ordre décroissant comme suit:
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
Cependant, je ne peux pas comprendre comment trier cela dans l'ordre croissant.
// i'd like: 100, 101, 102, null, null
8 réponses
Essayez de mettre les deux colonnes dans le même orderby.
orderby p.LowestPrice.HasValue descending, p.LowestPrice
Sinon, chaque orderby est une opération distincte sur la collection qui la réorganise à chaque fois.
Cela devrait ordonner ceux avec un avec une valeur en premier, "puis" l'ordre de la valeur.
Cela aide vraiment à comprendre la syntaxe de la requête LINQ et comment elle est traduite en appels de méthode LINQ.
, Il s'avère que
var products = from p in _context.Products
where p.ProductTypeId == 1
orderby p.LowestPrice.HasValue descending
orderby p.LowestPrice descending
select p;
Sera traduit par le compilateur en
var products = _context.Products
.Where(p => p.ProductTypeId == 1)
.OrderByDescending(p => p.LowestPrice.HasValue)
.OrderByDescending(p => p.LowestPrice)
.Select(p => p);
Ce n'est absolument pas ce que vous voulez. Il trie par Product.LowestPrice.HasValue
dans descending
l'ordre et puis re-trie l'ensemble de la collection par Product.LowestPrice
dans descending
commande.
Ce que vous voulez est
var products = _context.Products
.Where(p => p.ProductTypeId == 1)
.OrderByDescending(p => p.LowestPrice.HasValue)
.ThenBy(p => p.LowestPrice)
.Select(p => p);
Que vous pouvez obtenir en utilisant la syntaxe de requête par
var products = from p in _context.Products
where p.ProductTypeId == 1
orderby p.LowestPrice.HasValue descending,
p.LowestPrice
select p;
Pour plus de détails sur les traductions de syntaxe de requête aux appels de méthode, voir la spécification de langue. Sérieusement. La lire.
J'ai une autre option dans cette situation. Ma liste est objList, et je dois commander mais nulls doit être à la fin. ma décision:
var newList = objList.Where(m=>m.Column != null)
.OrderBy(m => m.Column)
.Concat(objList.where(m=>m.Column == null));
, La solution pour les valeurs de chaîne est vraiment bizarre:
.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString)
La seule raison pour laquelle cela fonctionne est que la première expression, OrderBy()
, trie les valeurs bool
: true
/false
. false
résultat aller en premier suivi par le résultat true
(nullables) et ThenBy()
trier les valeurs non nulles par ordre alphabétique.
Donc, je préfère faire quelque chose de plus lisible comme ceci:
.OrderBy(f => f.SomeString ?? "z")
Si SomeString
est null, il sera remplacé par "z"
et ensuite tout Trier par ordre alphabétique.
NOTE: Ceci est pas une solution ultime puisque "z"
VA en premier lieu que les valeurs z comme zebra
.
UPDATE 9/6/2016-A propos du commentaire @jornhd, c'est vraiment une bonne solution, mais c'est quand même un peu complexe, donc je vais recommander de l'envelopper dans une classe D'Extension, comme ceci:
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);
}
}
Et simple l'utiliser comme:
var sortedList = list.NullableOrderBy(f => f.SomeString);
Ma décision:
Array = _context.Products.OrderByDescending(p => p.Val ?? float.MinValue)
C'est ce que je suis venu avec parce que j'utilise des méthodes d'extension et aussi mon article est une chaîne, donc pas .HasValue
:
.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString)
Cela fonctionne avec les objets LINQ 2 en mémoire. Je ne l'ai pas testé avec EF ou N'importe quel DB ORM.
J'essayais de trouver une solution LINQ à cela mais je n'ai pas pu le résoudre à partir des réponses ici.
Ma réponse finale était:
.OrderByDescending(p.LowestPrice.HasValue).ThenBy(p.LowestPrice)
Ci-dessous est la méthode d'extension pour vérifier la valeur null si vous voulez trier sur la propriété enfant d'un 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);
}
Et simple l'utiliser comme:
var sortedList = list.NullableOrderBy(x => x.someObject, y => y.someObject?.someProperty);