Como obter o valor máximo de uma coluna usando o Entity Framework?

94

Para obter o valor máximo de uma coluna que contém um inteiro, posso usar o seguinte comando T-SQL

SELECT MAX(expression )
FROM tables
WHERE predicates;

É possível obter o mesmo resultado com Entity Framework.

Digamos que tenho o seguinte modelo

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

Como faço para saber a idade da pessoa mais velha?

int maxAge = context.Persons.?
Richard77
fonte

Respostas:

155

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

E certifique-se de ter using System.Linq;no topo do seu arquivo

Krolik
fonte
2
Lutei um pouco com isso porque senti falta do "using System.Linq;" Você deve considerar adicionar essa informação à sua resposta para novatos como eu :)
RagnaRock
2
Sem problemas @RagnaRock
krolik
3
Mas e se você não tiver nenhum registro e erros de EF trows. Minha adição var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (model! = null) {var val = db.BillOfLading.Max (x => x.No);
HerGiz
Isso é eficiente? Ou seria melhor ter uma estrutura de entidade para executar um procedimento armazenado que usa a função Max? Novo no framework de entidades e estou genuinamente curioso
TemporaryFix
@Programático absolutamente nenhuma razão que seria mais eficiente. Exceto na versão Sql Server <= 7.
mxmissile
55

Se a lista estiver vazia, recebo uma exceção. Esta solução levará em consideração este problema:

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();
Carlos Toledo
fonte
8
Esta deve ser a resposta aceita. Apenas uma viagem de ida e volta para o servidor e sem exceções.
junho de
4
Mas ele recupera todos os valores de coluna do banco de dados e aplica Max no lado do aplicativo.
SuperDuck
2
Isso faz 3 subconsultas. Eu propus uma resposta diferente.
jsgoupil
4
apenas uma nota lateral - isso não funciona com o núcleo EF. Eu usei:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs
11

Ou você pode tentar isto:

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

Talvez ajude, se você quiser adicionar algum filtro:

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

Ou algo nesse sentido.

EJ Brennan
fonte
4

Sua coluna é anulável

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

Sua coluna não é anulável

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

Em ambos os casos, você pode usar o segundo código. Se você usar DefaultIfEmpty, fará uma consulta maior no seu servidor. Para as pessoas interessadas, aqui estão os equivalentes EF6:

Consulta sem DefaultIfEmpty

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

Consultar com 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
fonte
2
E sobreint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs
3

Como muitos disseram - esta versão

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

lança uma exceção quando a tabela está vazia.

Usar

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

ou

int maxAge = context.Persons.Select(x => x.Age).DefaultIfEmpty(0).Max()
AK
fonte
sua segunda resposta parece boa para mim, se alguém olhar o SQL gerado, a segunda resposta é boa.
Deepak Sharma
2

Em VB.Net seria

Dim maxAge As Integer = context.Persons.Max(Function(p) p.Age)
dipi mal
fonte
2
int maxAge = context.Persons.Max(p => p.Age);

Esta versão, se a lista estiver vazia :

  • Retorna null- para sobrecargas anuláveis
  • Lança Sequence contains no elementexceção - para sobrecargas não anuláveis

-

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

Esta versão lida com o caso de lista vazia, mas gera uma consulta mais complexa e, por algum motivo, não funciona com EF Core.

-

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

Esta versão é elegante e eficiente (consulta simples e ida e volta ao banco de dados), funciona com EF Core. Ele lida com a exceção mencionada acima convertendo o tipo não anulável em anulável e, em seguida, aplicando o valor padrão usando o ??operador.

seidme
fonte
1

A resposta selecionada gera exceções, e a resposta de Carlos Toledo aplica a filtragem após recuperar todos os valores do banco de dados.

O seguinte executa uma única viagem de ida e volta e lê um único valor, usando qualquer índice possível, sem exceção.

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