¿Cómo obtener el valor máximo de una columna usando Entity Framework?

92

Para obtener el valor máximo de una columna que contiene un número entero, puedo usar el siguiente comando T-SQL

SELECT MAX(expression )
FROM tables
WHERE predicates;

¿Es posible obtener el mismo resultado con Entity Framework?

Digamos que tengo el siguiente modelo

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

¿Cómo obtengo la edad de la persona mayor?

int maxAge = context.Persons.?
Richard77
fuente

Respuestas:

152

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

Y asegúrese de tener using System.Linq;en la parte superior de su archivo

krolik
fuente
2
Luché un poco con esto porque me perdí el "uso de System.Linq;" Deberías considerar agregar esa información a tu respuesta para novatos como yo :)
RagnaRock
2
No hay problema @RagnaRock
krolik
3
Pero, ¿qué pasa si no tiene ningún registro y EF trows errores? Mi adición var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (modelo! = nulo) {var val = db.BillOfLading.Max (x => x.No);
HerGiz
¿Es esto eficiente? ¿O sería mejor que el marco de la entidad ejecute un procedimiento almacenado que use la función Max? Nuevo en el marco de la entidad y realmente tengo curiosidad
TemporaryFix
@Programmatic absolutamente ninguna razón por la que sería más eficiente. Excepto en la versión de Sql Server <= 7.
mxmissile
49

Si la lista está vacía, obtengo una excepción. Esta solución tendrá en cuenta este problema:

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();
Carlos toledo
fuente
7
Esta debería ser la respuesta aceptada. Solo un viaje de ida y vuelta al servidor y sin excepciones.
9Rune5
4
Pero recupera todos los valores de columna de la base de datos y aplica Max en el lado de la aplicación.
SuperDuck
1
Esto hace 3 subconsultas. Propuse una respuesta diferente.
jsgoupil
3
solo una nota al margen: esto no funciona con EF core. await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
Usé
11

O puedes probar esto:

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

Tal vez ayude, si desea agregar algún filtro:

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

O algo por el estilo.

EJ Brennan
fuente
4

Tu columna es anulable

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

Tu columna no admite nulos

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

En ambos casos, puede utilizar el segundo código. Si utilizaDefaultIfEmpty , hará una consulta más grande en su servidor. Para las personas que estén interesadas, aquí está el equivalente EF6:

Consulta sin DefaultIfEmpty

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

Consulta 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]
jsgoupil
fuente
1
¿Qué pasa conint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs
3

Como muchos dijeron, esta versión

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

lanza una excepción cuando la tabla está vacía.

Utilizar

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

o

int maxAge = context.Persons.Select(x => x.Age).DefaultIfEmpty(0).Max()
Alaska
fuente
su segunda respuesta me parece bien, si alguien mira SQL generado, la segunda respuesta es buena.
Deepak Sharma
2

En VB.Net sería

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

Esta versión, si la lista está vacía :

  • Devoluciones null : para sobrecargas que valores NULL
  • Lanza una Sequence contains no elementexcepción: para sobrecargas que no aceptan valores NULL

-

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

Esta versión maneja el caso de lista vacía, pero genera consultas más complejas y, por alguna razón, no funciona con EF Core.

-

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

Esta versión es elegante y eficiente (consulta simple y ida y vuelta a la base de datos), funciona con EF Core. Maneja la excepción mencionada anteriormente convirtiendo el tipo no anulable en anulable y luego aplicando el valor predeterminado usando el ??operador.

seidme
fuente
1

La respuesta seleccionada arroja excepciones y la respuesta de Carlos Toledo aplica filtrado después de recuperar todos los valores de la base de datos.

El siguiente ejecuta un solo viaje de ida y vuelta y lee un solo valor, utilizando cualquier índice posible, sin excepción.

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