Come ottenere il valore massimo di una colonna utilizzando Entity Framework?


92

Per ottenere il valore massimo di una colonna che contiene un numero intero, posso utilizzare il seguente comando T-SQL

SELECT MAX(expression )
FROM tables
WHERE predicates;

È possibile ottenere lo stesso risultato con Entity Framework.

Diciamo che ho il seguente modello

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

Come ottengo l'età della persona più anziana?

int maxAge = context.Persons.?

Risposte:


152

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

E assicurati di avere using System.Linq;all'inizio del file


2
Ho lottato un po 'con questo perché mi mancava "using System.Linq;" Dovresti considerare di aggiungere queste informazioni alla tua risposta ai neofiti come me :)
RagnaRock

2
Nessun problema @RagnaRock
krolik

3
Ma cosa succede se non si hanno record e EF trow errori. La mia aggiunta var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (model! = null) {var val = db.BillOfLading.Max (x => x.No);
HerGiz

È efficiente? O sarebbe meglio che il framework di entità esegua una stored procedure che utilizza la funzione Max? Nuovo al framework dell'entità e sono sinceramente curioso
TemporaryFix

@Programmatic assolutamente nessun motivo che sarebbe più efficiente. Ad eccezione della versione Sql Server <= 7.
mxmissile

49

Se l'elenco è vuoto ottengo un'eccezione. Questa soluzione terrà conto di questo problema:

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

7
Questa dovrebbe essere la risposta accettata. Solo un viaggio di andata e ritorno al server e nessuna eccezione.
9Rune5

4
Ma recupera tutti i valori di colonna dal database e applica Max sul lato dell'applicazione.
SuperDuck

1
Questo fa 3 sottoquery. Ho proposto una risposta diversa.
jsgoupil

3
solo una nota a margine: questo non funziona con EF core. Ho usato:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs

11

Oppure puoi provare questo:

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

7

Forse aiuto, se vuoi aggiungere qualche filtro:

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


4

La tua colonna è annullabile

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

La tua colonna non è annullabile

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

In entrambi i casi puoi utilizzare il secondo codice. Se lo usi DefaultIfEmpty, farai una query più grande sul tuo server. Per le persone interessate, ecco l'equivalente EF6:

Interroga senza DefaultIfEmpty

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

Interroga con 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
Che direint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs

3

Come molti hanno detto - questa versione

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

genera un'eccezione quando la tabella è vuota.

Uso

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

o

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

la tua seconda risposta mi sembra buona, se qualcuno guarda l'SQL generato, la seconda risposta è buona.
Deepak Sharma

2

In VB.Net lo sarebbe

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

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

Questa versione, se l'elenco è vuoto :

  • Restituisce null: per gli overload nullable
  • Genera Sequence contains no elementun'eccezione: per gli overload non nullable

-

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

Questa versione gestisce il caso dell'elenco vuoto, ma genera query più complesse e per qualche motivo non funziona con EF Core.

-

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

Questa versione è elegante e performante (query semplice e singolo round trip al database), funziona con EF Core. Gestisce l'eccezione menzionata sopra eseguendo il cast del tipo non nullable su nullable e quindi applicando il valore predefinito usando l' ??operatore.


1

La risposta selezionata genera eccezioni e la risposta di Carlos Toledo applica il filtro dopo aver recuperato tutti i valori dal database.

Il seguente esegue un singolo round trip e legge un singolo valore, utilizzando tutti gli indici possibili, senza eccezioni.

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.