Comment obtenir la valeur maximale d'une colonne à l'aide d'Entity Framework?


92

Pour obtenir la valeur maximale d'une colonne contenant un entier, je peux utiliser la commande T-SQL suivante

SELECT MAX(expression )
FROM tables
WHERE predicates;

Est-il possible d'obtenir le même résultat avec Entity Framework.

Disons que j'ai le modèle suivant

public class Person
{
  public int PersonID { get; set; }
  public int Name { get; set; }
  public int Age { get; set; }
}

Comment obtenir l'âge de la personne la plus âgée?

int maxAge = context.Persons.?

Réponses:


152

Essaye ça int maxAge = context.Persons.Max(p => p.Age);

Et assurez-vous que vous avez using System.Linq;en haut de votre fichier


2
Je me suis un peu dérangé avec cela parce que j'ai raté le "using System.Linq;" Vous devriez envisager d'ajouter cette information à votre réponse aux débutants comme moi :)
RagnaRock

2
Pas de problème @RagnaRock
krolik

3
Mais que se passe-t-il si vous n'avez aucun enregistrement et que EF trows erreurs. Mon ajout var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (model! = null) {var val = db.BillOfLading.Max (x => x.No);
HerGiz

Est-ce efficace? Ou serait-il préférable que le framework d'entité exécute une procédure stockée qui utilise la fonction Max? Nouveau dans le cadre d'entité et je suis vraiment curieux
TemporaryFix

@Programmatic absolument aucune raison qui serait plus efficace. Sauf sur Sql Server version <= 7.
mxmissile

49

Si la liste est vide, j'obtiens une exception. Cette solution prendra en compte ce problème:

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();

7
Cela devrait être la réponse acceptée. Un seul aller-retour vers le serveur et aucune exception.
9Rune5

4
Mais il récupère toutes les valeurs de colonne de la base de données et applique Max du côté de l'application.
SuperDuck

1
Cela fait 3 sous-requêtes. J'ai proposé une réponse différente.
jsgoupil

3
juste une note latérale - cela ne fonctionne pas avec EF core. J'ai utilisé:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs le

11

Ou vous pouvez essayer ceci:

(From p In context.Persons Select p Order By age Descending).FirstOrDefault

7

Peut-être aider, si vous souhaitez ajouter un filtre:

context.Persons
.Where(c => c.state == myState)
.Select(c => c.age)
.DefaultIfEmpty(0)
.Max();


4

Votre colonne est nullable

int maxAge = context.Persons.Select(p => p.Age).Max() ?? 0;

Votre colonne n'est pas nullable

int maxAge = context.Persons.Select(p => p.Age).Cast<int?>().Max() ?? 0;

Dans les deux cas, vous pouvez utiliser le deuxième code. Si vous utilisez DefaultIfEmpty, vous ferez une requête plus importante sur votre serveur. Pour les personnes intéressées, voici l'équivalent EF6:

Requête sans DefaultIfEmpty

SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MAX([Extent1].[Age]) AS [A1]
        FROM [dbo].[Persons] AS [Extent1]
    )  AS [GroupBy1]

Requête avec DefaultIfEmpty

SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        MAX([Join1].[A1]) AS [A1]
        FROM ( SELECT 
            CASE WHEN ([Project1].[C1] IS NULL) THEN 0 ELSE [Project1].[Age] END AS [A1]
            FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
            LEFT OUTER JOIN  (SELECT 
                [Extent1].[Age] AS [Age], 
                cast(1 as tinyint) AS [C1]
                FROM [dbo].[Persons] AS [Extent1]) AS [Project1] ON 1 = 1
        )  AS [Join1]
    )  AS [GroupBy1]

1
Qu'en est-ilint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs le

3

Comme beaucoup l'ont dit - cette version

int maxAge = context.Persons.Max(p => p.Age);

lève une exception lorsque la table est vide.

Utilisation

int maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;

ou

int maxAge = context.Persons.Select(x => x.Age).DefaultIfEmpty(0).Max()

votre deuxième réponse me semble bonne, si quelqu'un regarde le SQL généré, la deuxième réponse est bonne.
Deepak Sharma

2

Dans VB.Net, ce serait

Dim maxAge As Integer = context.Persons.Max(Function(p) p.Age)

2
int maxAge = context.Persons.Max(p => p.Age);

Cette version, si la liste est vide :

  • Renvoie null- pour les surcharges Nullable
  • Lève une Sequence contains no elementexception - pour les surcharges non nulles

-

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();

Cette version gère la casse de liste vide, mais elle génère une requête plus complexe et, pour une raison quelconque, ne fonctionne pas avec EF Core.

-

int maxAge = context.Persons.Max(p => (int?)p.Age) ?? 0;

Cette version est élégante et performante (requête simple et aller-retour unique vers la base de données), fonctionne avec EF Core. Il gère l'exception mentionnée ci-dessus en convertissant le type non nullable en nullable, puis en appliquant la valeur par défaut à l'aide de l' ??opérateur.


1

La réponse sélectionnée lève des exceptions et la réponse de Carlos Toledo applique le filtrage après avoir récupéré toutes les valeurs de la base de données.

Le suivant exécute un seul aller-retour et lit une seule valeur, en utilisant tous les index possibles, sans exception.

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.