215 votes

Valeur maximale de retour si la requête est vide

J'ai cette question :

int maxShoeSize = Workers
    .Where(x => x.CompanyId == 8)
    .Max(x => x.ShoeSize);

Ce qui sera dans maxShoeSize si l'entreprise 8 n'a pas de travailleurs du tout ?

UPDATE :
Comment puis-je modifier la requête afin d'obtenir 0 et non une exception ?

0 votes

Naor : avez-vous entendu parler de LINQPad ?

3 votes

Je ne comprends pas pourquoi vous demandez : "Qu'est-ce qui sera dans ? maxShoeSize ?" si vous l'aviez déjà essayé.

0 votes

@jwg : Je suppose que je voulais voir si vous connaissez la réponse :) Finalement, j'ai trouvé une meilleure façon de faire ce que j'ai demandé et c'est ce que je voulais dire.

375voto

Ron K. Points 3442
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                         .Select(x => x.ShoeSize)
                         .DefaultIfEmpty(0)
                         .Max();

Le zéro dans DefaultIfEmpty n'est pas nécessaire.

0 votes

Fonctionne :) Mais dans mon code, le zéro dans DefaultIfEmpty était nécessaire.

2 votes

En ce qui concerne la première partie de la question, qui n'a pas reçu de réponse complète ici : Selon la documentation officielle si le type générique de l vide est un type de référence, vous obtenez null. Sinon, selon cette question en appelant Max() sur une séquence vide entraîne une erreur.

2 votes

Ce site ne fonctionnera pas pour EF Core 3.1 et les versions ultérieures si le type n'est pas nullable. La raison est qu'il y a une jointure gauche pour toutes les entrées qui échouera pour les types non-nulables. Utilisez Workers.Where(...).Max(x => (int?)x) ?? 0; . Cela génère une requête max efficace directement en sql.

76voto

CptRobby Points 315

Je sais qu'il s'agit d'une vieille question et que la réponse acceptée fonctionne, mais cette question a répondu à ma question de savoir si un tel ensemble vide entraînerait une exception ou une default(int) résultat.

La réponse acceptée, bien qu'elle fonctionne, n'est pas la solution idéale à mon avis, et elle n'est pas donnée ici. C'est pourquoi je la fournis dans ma propre réponse pour le bénéfice de tous ceux qui la recherchent.

Le code original de l'OP était :

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);

Voici comment je l'écrirais pour éviter les exceptions et fournir un résultat par défaut :

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;

Ainsi, le type de retour de la fonction Max pour être int? qui permet à l null et ensuite le ?? remplace le null résultat avec 0 .


EDITAR
Juste pour clarifier quelque chose dans les commentaires, Entity Framework ne supporte pas actuellement l'option as La façon de l'écrire en travaillant avec EF serait donc la suivante :

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max<[TypeOfWorkers], int?>(x => x.ShoeSize) ?? 0;

Depuis le [TypeOfWorkers] peut être un long nom de classe et est fastidieux à écrire, j'ai ajouté une méthode d'extension pour vous aider.

public static int MaxOrDefault<T>(this IQueryable<T> source, Expression<Func<T, int?>> selector, int nullValue = 0)
{
    return source.Max(selector) ?? nullValue;
}

Ceci ne traite que int mais on pourrait faire de même pour long , double ou tout autre type de valeur dont vous avez besoin. L'utilisation de cette méthode d'extension est très simple, il vous suffit de passer votre fonction de sélection et d'inclure éventuellement une valeur à utiliser pour null, qui prend la valeur 0 par défaut :

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);

J'espère que cela aidera encore plus les gens.

35voto

Frédéric Hamidi Points 123646

Max() ne retournera rien dans ce cas.

Il permettra d'augmenter InvalidOperationException puisque la source ne contient aucun élément.

3 votes

Cela ne fera qu'augmenter InvalidOperationException si les objets de la liste sont d'un type non nul : docs.microsoft.com/fr/us/dotnet/api/

0 votes

Vous parlez du monde Max méthode. La question porte sur une requête, la méthode discutée est donc la suivante Queryable.Max . Il peut être similaire mais, par exemple, la documentation n'indique pas qu'il jette un InvalidOperationException

19voto

Danny Chen Points 14781
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();

13voto

abkonsta Points 281

Si c'est Linq to SQL, je n'aime pas utiliser Any() parce qu'il en résulte de multiples requêtes au serveur SQL.

Si ShoeSize n'est pas un champ annulable, alors l'utilisation de l'option .Max(..) ?? 0 ne fonctionnera pas, mais la suivante le fera :

int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;

Il ne change absolument pas le SQL émis, mais il renvoie 0 si la séquence est vide parce qu'il modifie l'élément Max() pour renvoyer un int? au lieu d'un int .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X