122

To get maximum value of a column that contains integer, I can use the following T-SQL comand

SELECT MAX(expression )
FROM tables
WHERE predicates;

Is it possible to obtain the same result with Entity Framework.

Let's say I have the following model

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

How do I get the oldest person's age?

int maxAge = context.Persons.?
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Richard77
  • 20,343
  • 46
  • 150
  • 252

10 Answers10

185

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

And make sure you have using System.Linq; at the top of your file

krolik
  • 5,712
  • 1
  • 26
  • 30
  • 4
    I strugled a bit with this because I missed the "using System.Linq;" You should consider adding that info to your answer to newbies like me :) – RagnaRock Nov 23 '15 at 18:22
  • 2
    No problem @RagnaRock – krolik Nov 23 '15 at 19:06
  • 5
    But what if you don't have any records and EF trows errors. My addition var model = db.BillOfLading.Select(x => x.No).LastOrDefault(); if (model != null) { var val = db.BillOfLading.Max(x => x.No); – HerGiz Feb 19 '16 at 11:23
  • Is this efficient? Or would it be better to have entity framework execute a stored procedure that uses the Max function? New to entity framework and am genuinely curious – TemporaryFix Sep 12 '18 at 20:23
  • @Programmatic absolutely no reason that would be more efficient. Except on Sql Server version <= 7. – mxmissile Mar 28 '19 at 20:24
  • Even with `using System.Linq`, in `Web API` I get the intellisense error "the name 'context' does not exist in the current context. Is it correct that this should go in the controller? I'm trying to put it inside one of my CRUD methods, but have also tried other areas in the controller to no avail :( – Kyle Vassella Apr 23 '19 at 15:57
  • @KyleVassella - your web API's data context variable may be named differently. If you scaffolded your API controller using Visual Studio built-in defaults, the API controllers have a single `db` field (which is the EF data context) for the whole class, and within the body of any of your methods you can access it directly. When the web request is over, there are scaffolded Dispose methods that take care of cleaning up the `db` variable. – bkwdesign Jan 21 '20 at 19:31
  • 2
    Good for async in EF Core: await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0 – egmfrs Jan 23 '20 at 15:42
73

If the list is empty I get an exception. This solution will take into account this issue:

int maxAge = context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max();
Carlos Toledo
  • 2,519
  • 23
  • 23
15
int maxAge = context.Persons.Max(p => p.Age); 

The version above, if the list is empty:

  • Returns null ― for nullable overloads
  • Throws Sequence contains no element exception ― for non-nullable overloads

_

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

The version above handles the empty list case, but it generates more complex query, and for some reason doesn't work with EF Core.

_

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

This version is elegant and performant (simple query and single round-trip to the database), works with EF Core. It handles the mentioned exception above by casting the non-nullable type to nullable and then applying the default value using the ?? operator.

seidme
  • 12,543
  • 5
  • 36
  • 40
  • using `context.Persons.Max(p => (int?)p.Age) ?? 0` work fine in ef core 5.0, and for some reason this one `context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max()` cannot be translated, so ef core 5.0 throw an exception. – James Feb 05 '21 at 10:06
  • This `context.Persons.Select(p => p.Age).DefaultIfEmpty(0).Max()` one also does not with EF Core 3.0 and I used the `context.Persons.Max(p => (int?)p.Age) ?? 0`. – Seyedraouf Modarresi May 24 '21 at 16:59
13

Or you can try this:

(From p In context.Persons Select p Order By age Descending).FirstOrDefault
danicode
  • 807
  • 9
  • 17
8

Maybe help, if you want to add some filter:

context.Persons
.Where(c => c.state == myState)
.Select(c => c.age)
.DefaultIfEmpty(0)
.Max();
Foy
  • 181
  • 2
  • 4
8

Your column is nullable

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

Your column is non-nullable

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

In both cases, you can use the second code. If you use DefaultIfEmpty, you will do a bigger query on your server. For people who are interested, here are the EF6 equivalent:

Query without DefaultIfEmpty

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

Query with 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
  • 3,788
  • 3
  • 38
  • 53
5

Selected answer throws exceptions, and the answer from Carlos Toledo applies filtering after retrieving all values from the database.

The following one runs a single round-trip and reads a single value, using any possible indexes, without an exception.

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
DarkWingDuck
  • 2,028
  • 1
  • 22
  • 30
5
maxAge = Persons.Max(c => c.age)

or something along those lines.

VansFannel
  • 45,055
  • 107
  • 359
  • 626
E.J. Brennan
  • 45,870
  • 7
  • 88
  • 116
4

As many said - this version

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

throws an exception when table is empty.

Use

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

or

int maxAge = context.Persons.Select(x => x.Age).DefaultIfEmpty(0).Max()
A K
  • 714
  • 17
  • 39
2

In VB.Net it would be

Dim maxAge As Integer = context.Persons.Max(Function(p) p.Age)
brasofilo
  • 25,496
  • 15
  • 91
  • 179
dipi evil
  • 489
  • 1
  • 11
  • 20