Wie erhalte ich mit Entity Framework den Maximalwert einer Spalte?

87

Um den Maximalwert einer Spalte zu erhalten, die eine Ganzzahl enthält, kann ich den folgenden T-SQL-Befehl verwenden

SELECT MAX(expression )
FROM tables
WHERE predicates;

Ist es möglich, mit Entity Framework das gleiche Ergebnis zu erzielen?

Angenommen, ich habe das folgende Modell

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

Wie erhalte ich das Alter der ältesten Person?

int maxAge = context.Persons.?
Richard77
quelle

Antworten:

148

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

Und stellen Sie sicher, dass Sie using System.Linq;oben in Ihrer Datei haben

krolik
quelle
1
Ich hatte ein bisschen Probleme damit, weil ich das "using System.Linq;" Sie sollten erwägen, diese Informationen zu Ihrer Antwort an Neulinge wie mich
hinzuzufügen
2
Kein Problem @RagnaRock
krolik
3
Aber was ist, wenn Sie keine Datensätze haben und EF Fehler löscht? Mein Zusatz var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (model! = null) {var val = db.BillOfLading.Max (x => x.No);
HerGiz
Ist das effizient? Oder wäre es besser, wenn das Entity Framework eine gespeicherte Prozedur ausführt, die die Max-Funktion verwendet? Neu im Entity Framework und bin wirklich neugierig
TemporaryFix
@Programmatic absolut kein Grund, der effizienter wäre. Außer auf SQL Server Version <= 7.
mxmissile
49

Wenn die Liste leer ist, bekomme ich eine Ausnahme. Diese Lösung berücksichtigt dieses Problem:

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();
Carlos Toledo
quelle
7
Dies sollte die akzeptierte Antwort sein. Nur eine Hin- und Rückfahrt zum Server und keine Ausnahmen.
9Rune5
4
Es werden jedoch alle Spaltenwerte aus der Datenbank abgerufen und Max auf der Anwendungsseite angewendet.
SuperDuck
1
Dies macht 3 Unterabfragen. Ich schlug eine andere Antwort vor.
Jsgoupil
2
Nur eine Randnotiz - dies funktioniert nicht mit EF Core. Ich benutzte:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs
10

Oder Sie können dies versuchen:

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

Vielleicht helfen Sie, wenn Sie einen Filter hinzufügen möchten:

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

oder so ähnlich.

EJ Brennan
quelle
4

Ihre Spalte ist nullbar

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

Ihre Spalte ist nicht nullwertfähig

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

In beiden Fällen können Sie den zweiten Code verwenden. Wenn Sie verwenden DefaultIfEmpty, führen Sie eine größere Abfrage auf Ihrem Server durch. Für Interessierte gibt es hier das EF6-Äquivalent:

Abfrage ohne DefaultIfEmpty

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

Abfrage mit 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
quelle
Was ist mitint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs
2

In VB.Net wäre es

Dim maxAge As Integer = context.Persons.Max(Function(p) p.Age)
Dipi böse
quelle
2

Wie viele sagten - diese Version

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

löst eine Ausnahme aus, wenn die Tabelle leer ist.

Verwenden

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

oder

int maxAge = context.Persons.Select(x => x.Age).DefaultIfEmpty(0).Max()
AK
quelle
Ihre zweite Antwort sieht für mich gut aus. Wenn sich jemand generiertes SQL ansieht, ist die zweite Antwort gut.
Deepak Sharma
2
int maxAge = context.Persons.Max(p => p.Age);

Diese Version, wenn die Liste leer ist :

  • Rückgabe null- für nullbare Überladungen
  • Löst eine Sequence contains no elementAusnahme aus - für nicht nullbare Überladungen

- -

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

Diese Version behandelt den Fall einer leeren Liste, generiert jedoch komplexere Abfragen und funktioniert aus irgendeinem Grund nicht mit EF Core.

- -

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

Diese Version ist elegant und performant (einfache Abfrage und einmaliger Roundtrip zur Datenbank) und funktioniert mit EF Core. Die oben erwähnte Ausnahme wird behandelt, indem der nicht nullbare Typ in nullable umgewandelt und dann der Standardwert mithilfe des ??Operators angewendet wird .

seidme
quelle
1

Die ausgewählte Antwort löst Ausnahmen aus, und die Antwort von Carlos Toledo wendet die Filterung an, nachdem alle Werte aus der Datenbank abgerufen wurden.

Der folgende führt einen einzelnen Roundtrip aus und liest ausnahmslos einen einzelnen Wert unter Verwendung möglicher Indizes.

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
SuperDuck
quelle