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.?
Richard77
la source

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

Krolik
la source
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();
Carlos Toledo
la source
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
danicode
la source
7

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

context.Persons
.Where(c => c.state == myState)
.Select(c => c.age)
.DefaultIfEmpty(0)
.Max();
Foy
la source
4
maxAge = Persons.Max(c => c.age)

Ou quelque chose de ce genre.

EJ Brennan
la source
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]
jsgoupil
la source
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()
AK
la source
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)
dipi mal
la source
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.

seidme
la source
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();
SuperDuck
la source