Ordre LINQ par colonne null où l’ordre est croissant et les null doivent être en dernier

J’essaie de sortinger une liste de produits par leur prix.

Le jeu de résultats doit répertorier les produits par prix de bas en haut par la colonne LowestPrice . Cependant, cette colonne est nullable.

Je peux sortinger la liste par ordre décroissant comme ceci:

 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 sortinger cela en ordre croissant.

 // i'd like: 100, 101, 102, null, null 

Essayez de mettre les deux colonnes dans le même ordre.

 orderby p.LowestPrice.HasValue descending, p.LowestPrice 

Sinon, chaque commande est une opération distincte de la collection qui la réorganise à chaque fois.

Cela devrait ordonner ceux avec un avec une valeur d’abord, “alors” l’ordre de la valeur.

Cela aide vraiment à comprendre la syntaxe de requête LINQ et comment elle est traduite en appels de méthode LINQ.

Il se trouve 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 pour

 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. Cela sortinge par Product.LowestPrice.HasValue dans descending ordre descending , puis re-sortinge la collection entière par Product.LowestPrice dans descending ordre descending .

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 la syntaxe de requête en appels de méthode, voir la spécification de langage. Sérieusement. Lis le.

J’ai une autre option dans cette situation. Ma liste est objList, et je dois commander mais les null doivent ê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 étrange:

 .OrderBy(f => f.SomeSsortingng == null).ThenBy(f => f.SomeSsortingng) 

La seule raison qui fonctionne est que la première expression, OrderBy() , sortinge les valeurs bool : true / false . false résultat false va d’abord suivre le résultat true (nullables) et ThenBy() sortinge les valeurs non nulles par ordre alphabétique.

Donc, je préfère faire quelque chose de plus lisible comme celui-ci:

 .OrderBy(f => f.SomeSsortingng ?? "z") 

Si SomeSsortingng est null, il sera remplacé par "z" , puis SomeSsortingng par ordre alphabétique.

NOTE: Ceci n’est pas une solution ultime puisque "z" passe en premier lieu par rapport aux valeurs z telles que zebra .

MISE À JOUR 06/09/2016 – À propos de @jornhd comment, c’est vraiment une bonne solution, mais c’est quand même un peu complexe, alors je vous recommande de l’envelopper dans une classe d’extension, telle que celle-ci:

 public static class MyExtensions { public static IOrderedEnumerable NullableOrderBy(this IEnumerable list, Func keySelector) { return list.OrderBy(v => keySelector(v) != null ? 0 : 1).ThenBy(keySelector); } } 

Et simple l’utiliser comme:

 var sortedList = list.NullableOrderBy(f => f.SomeSsortingng); 

ma décision:

 Array = _context.Products.OrderByDescending(p => p.Val ?? float.MinValue) 

C’est ce que j’ai trouvé parce que j’utilise des méthodes d’extension et que mon object est une chaîne, donc non .HasValue :

 .OrderBy(f => f.SomeSsortingng == null).ThenBy(f => f.SomeSsortingng) 

Cela fonctionne avec les objects 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 ne pouvais pas y arriver avec les réponses.

Ma dernière réponse était:

 .OrderByDescending(p.LowestPrice.HasValue).ThenBy(p.LowestPrice) 

La méthode d’extension ci-dessous permet de vérifier la valeur null si vous souhaitez sortinger la propriété enfant d’un sélecteur de clés.

 public static IOrderedEnumerable NullableOrderBy(this IEnumerable list, Func parentKeySelector, Func 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);