202 votes

LINQ: Max ou par défaut?

Quelle est la meilleure façon de tirer le maximum de valeur à partir d'une requête LINQ qui peut revenir pas de lignes? Si je ne l'

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter).Max

J'obtiens une erreur lors de la requête ne retourne aucune ligne. Je pourrais le faire

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter _
         Order By MyCounter Descending).FirstOrDefault

mais qui se sent un peu obtus pour une simple demande. Ai-je raté une meilleure façon de le faire?

Mise à JOUR: Voici l'histoire: je suis en train de récupérer la prochaine admissibilité compteur à partir d'une table d'enfant (système d'héritage, ne me lancez pas...). Le premier admissibilité à la ligne pour chaque patient est toujours de 1, le deuxième est de 2, etc. (évidemment, ce n'est pas la clé primaire de la table enfant). Donc, je suis en sélectionnant le max existants valeur du compteur pour un patient, puis en ajoutant 1 pour créer une nouvelle ligne. Lorsqu'il n'existe pas de valeurs enfant, j'ai besoin de la requête renvoie 0 (donc, l'ajout de 1 me donnera une contre-valeur de 1). Notez que je ne veux pas compter sur le brut nombre de lignes enfants, dans le cas de l'héritage application présente des lacunes dans les valeurs du compteur (possible). Mon mauvais pour essayer de faire de la question trop générique.

218voto

Jacob Proffitt Points 8187

Depuis DefaultIfEmpty n'est pas implémenté dans LINQ to SQL, j'ai fait une recherche sur l'erreur, il est retourné et a trouvé un article passionnant qui traite avec null définit dans des fonctions d'agrégation. Pour résumer ce que j'ai trouvé, vous pouvez contourner cette limitation en association à un nullable au sein de votre sélection. Mon VB est un peu rouillé, mais je pense que ça serait quelque chose comme ceci:

Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select CType(y.MyCounter, Integer?)).Max

Ou en C#

var x = (from y in context.MyTable
         where y.MyField == value
         select (int?)y.MyCounter).Max();

126voto

Eddie Deyo Points 2416

J'ai juste eu un problème semblable, mais j'utilisais des méthodes d'extension LINQ sur une liste plutôt qu'une syntaxe de requête. Le casting à un tour Nullable fonctionne aussi:

 int max = list.Max(i => (int?)i.MyCounter) ?? 0;
 

55voto

Jacob Proffitt Points 8187

Cela ressemble à un cas pour DefaultIfEmpty (le code non testé suit):

 Dim x = (From y In context.MyTable _
         Where y.MyField = value _
         Select y.MyCounter).DefaultIfEmpty.Max
 

37voto

yfeldblum Points 42613

Pensez à ce que vous demandez!

Le max de {1, 2, 3, -1, -2, -3} est évidemment 3. Le max de {2} est évidemment 2. Mais ce qui est le max de l'ensemble vide { }? Évidemment c'est une question de sens. Le max de l'ensemble vide n'est tout simplement pas défini. Tenter d'obtenir une réponse est une erreur mathématique. Le max de n'importe quel jeu doit être lui-même un élément de cet ensemble. L'ensemble vide n'a pas d'éléments pour affirmer que certaines nombre particulier, c'est le maximum de ce jeu sans être dans cet ensemble est une contradiction mathématique.

Tout comme c'est le comportement correct pour l'ordinateur pour lancer une exception lorsque le programmeur demande de diviser par zéro, donc c'est le comportement correct pour l'ordinateur pour lancer une exception lorsque le programmeur lui demande de prendre le max de l'ensemble vide. La Division par zéro, en prenant le max de l'ensemble vide, wiggering la spacklerorke, et de l'équitation, le flying unicorn à Neverland sont tous les sens, impossible, non défini.

Maintenant, qu'est-ce que vous avez réellement envie de faire?

26voto

David Schmitt Points 29384

Vous pouvez toujours ajouter Double.MinValue à la séquence. Cela garantirait qu'il y ait au moins un élément et que Max le renverrait seulement s'il est réellement le minimum. Pour déterminer quelle option est la plus efficace ( Concat , FirstOrDefault ou Take(1) ), vous devez effectuer une analyse comparative adéquate.

 double x = context.MyTable
    .Where(y => y.MyField == value)
    .Select(y => y.MyCounter)
    .Concat(new double[]{Double.MinValue})
    .Max();
 

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