Як отримати максимальне значення стовпця за допомогою Entity Framework?


92

Щоб отримати максимальне значення стовпця, що містить ціле число, я можу використовувати наступну команду T-SQL

SELECT MAX(expression )
FROM tables
WHERE predicates;

Чи можна отримати той самий результат за допомогою Entity Framework.

Скажімо, у мене така модель

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

Як отримати вік найстаршої людини?

int maxAge = context.Persons.?

Відповіді:


152

Спробуйте це int maxAge = context.Persons.Max(p => p.Age);

І переконайтеся, що у вас є using System.Linq;файл у верхній частині


2
Я трохи боровся з цим, бо пропустив "використання System.Linq;" Вам слід подумати про додавання цієї інформації до вашої відповіді новачкам, як я :)
RagnaRock

2
Немає проблем @RagnaRock
krolik

3
Але що, якщо у вас немає жодних записів і помилок EF видає. Моє додавання var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (модель! = нуль) {var val = db.BillOfLading.Max (x => x.No);
HerGiz

Це ефективно? Або було б краще, щоб фреймворк сутності виконував збережену процедуру, яка використовує функцію Max? Нове у структурі сутності і мені справді цікаво
TemporaryFix

@Programmatic абсолютно жодної причини, яка була б більш ефективною. За винятком версії Sql Server <= 7.
mxmissile

49

Якщо список порожній, я отримую виняток. Це рішення враховуватиме цю проблему:

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

7
Це має бути прийнятою відповіддю. Тільки один зворотній шлях до сервера і жодних винятків.
9Rune5,

4
Але він отримує всі значення стовпців з бази даних і застосовує Макс на стороні програми.
SuperDuck

1
Це робить 3 підзапити. Я запропонував іншу відповідь.
jsgoupil

3
лише примітка - це не працює з ядром EF. Я використовував:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs

11

Або ви можете спробувати це:

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

7

Можливо, допоможемо, якщо ви хочете додати якийсь фільтр:

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


4

Ваш стовпець має нульовий статус

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

Ваш стовпець не має нульового значення

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

В обох випадках ви можете використовувати другий код. Якщо ви використовуєте DefaultIfEmpty, ви зробите більший запит на своєму сервері. Для людей, яким цікаво, ось еквівалент EF6:

Запит без DefaultIfEmpty

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

Запит за допомогою 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]

1
А як щодоint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs

3

Як багато хто говорив - ця версія

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

видає виняток, коли таблиця порожня.

Використовуйте

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

або

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

Ваша друга відповідь виглядає добре для мене, якщо хтось дивиться на згенерований SQL, друга відповідь - це добре.
Діпак Шарма


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

Ця версія, якщо список порожній :

  • Повернення null - для перевантажень, що допускають нуль
  • Кидає Sequence contains no elementвиняток - для ненульованих перевантажень

-

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

Ця версія обробляє регістр порожнього списку, але він генерує більш складні запити, і з якихось причин не працює з EF Core.

-

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

Ця версія елегантна та продуктивна (простий запит та одноразовий зворотній перехід до бази даних), працює з EF Core. Він обробляє згаданий виняток вище, приводячи ненульований тип до нульового, а потім застосовуючи значення за замовчуванням за допомогою ??оператора.


1

Вибрана відповідь видає винятки, і відповідь від Карлоса Толедо застосовує фільтрацію після отримання всіх значень з бази даних.

Наступний запускає одну поїздку в обидва кінці і зчитує одне значення, використовуючи будь-які можливі індекси, без винятку.

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.