Jak uzyskać maksymalną wartość kolumny przy użyciu Entity Framework?

92

Aby uzyskać maksymalną wartość kolumny zawierającej liczbę całkowitą, mogę użyć następującego polecenia T-SQL

SELECT MAX(expression )
FROM tables
WHERE predicates;

Czy można uzyskać ten sam wynik w Entity Framework.

Powiedzmy, że mam następujący model

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

Jak określić wiek najstarszej osoby?

int maxAge = context.Persons.?
Richard77
źródło

Odpowiedzi:

152

Spróbuj tego int maxAge = context.Persons.Max(p => p.Age);

I upewnij się, że masz using System.Linq;u góry pliku

krolik
źródło
2
Trochę się z tym zmagałem, ponieważ przegapiłem „using System.Linq”; Powinieneś rozważyć dodanie tych informacji do swojej odpowiedzi dla początkujących, takich jak ja :)
RagnaRock
2
Żaden problem @RagnaRock
krolik
3
Ale co, jeśli nie masz żadnych rekordów, a EF wyświetla błędy. Mój dodatek var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (model! = null) {var val = db.BillOfLading.Max (x => x.No);
HerGiz
Czy to jest wydajne? A może lepiej byłoby, gdyby struktura jednostki wykonywała procedurę składowaną korzystającą z funkcji Max? Nowy we frameworku encji i jestem naprawdę ciekawy
TemporaryFix
@Programmatic absolutnie nie ma powodu, aby był bardziej wydajny. Z wyjątkiem wersji Sql Server <= 7.
mxmissile
49

Jeśli lista jest pusta, pojawia się wyjątek. To rozwiązanie uwzględni ten problem:

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();
Carlos Toledo
źródło
7
To powinna być akceptowana odpowiedź. Tylko jedna podróż w obie strony do serwera i bez wyjątków.
9Rune5
4
Ale pobiera wszystkie wartości kolumn z bazy danych i stosuje wartość Max po stronie aplikacji.
SuperDuck
1
To tworzy 3 podzapytania. Zaproponowałem inną odpowiedź.
jsgoupil
3
uwaga na marginesie - to nie działa z rdzeniem EF. Użyłem:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs
11

Lub możesz spróbować tego:

(From p In context.Persons Select p Order By age Descending).FirstOrDefault
danicode
źródło
7

Może pomóż, jeśli chcesz dodać jakiś filtr:

context.Persons
.Where(c => c.state == myState)
.Select(c => c.age)
.DefaultIfEmpty(0)
.Max();
Foy
źródło
4
maxAge = Persons.Max(c => c.age)

czy coś podobnego.

EJ Brennan
źródło
4

Twoja kolumna ma wartość null

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

Twoja kolumna nie dopuszcza wartości null

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

W obu przypadkach możesz użyć drugiego kodu. Jeśli używasz DefaultIfEmpty, wykonasz większe zapytanie na swoim serwerze. Dla zainteresowanych, oto odpowiednik EF6:

Zapytanie bez DefaultIfEmpty

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

Zapytanie z 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
źródło
1
A co zint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs
3

Jak wielu powiedziało - ta wersja

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

zgłasza wyjątek, gdy tabela jest pusta.

Posługiwać się

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

lub

int maxAge = context.Persons.Select(x => x.Age).DefaultIfEmpty(0).Max()
AK
źródło
Twoja druga odpowiedź wygląda dla mnie dobrze, jeśli ktoś spojrzy na wygenerowany SQL, druga odpowiedź jest dobra.
Deepak Sharma,
2

W VB.Net byłoby

Dim maxAge As Integer = context.Persons.Max(Function(p) p.Age)
dipi evil
źródło
2
int maxAge = context.Persons.Max(p => p.Age);

Ta wersja, jeśli lista jest pusta :

  • Zwraca null- dla przeciążeń dopuszczających wartość null
  • Zgłasza Sequence contains no elementwyjątek - dla przeciążeń niepodlegających wartości null

-

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

Ta wersja obsługuje pusty przypadek listy, ale generuje bardziej złożone zapytanie iz jakiegoś powodu nie działa z EF Core.

-

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

Ta wersja jest elegancka i wydajna (proste zapytanie i pojedyncza runda do bazy danych), współpracuje z EF Core. Obsługuje wspomniany wyjątek powyżej, rzutując typ niedopuszczający wartości null do wartości null, a następnie stosując wartość domyślną przy użyciu ??operatora.

seidme
źródło
1

Wybrana odpowiedź generuje wyjątki, a odpowiedź od Carlosa Toledo stosuje filtrowanie po pobraniu wszystkich wartości z bazy danych.

Poniższy uruchamia pojedynczą podróż w obie strony i odczytuje pojedynczą wartość przy użyciu dowolnych możliwych indeksów bez wyjątku.

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
SuperDuck
źródło