如何使用实体框架获取列的最大值?


92

要获取包含整数的列的最大值,我可以使用以下T-SQL命令

SELECT MAX(expression )
FROM tables
WHERE predicates;

是否有可能使用实体框架获得相同的结果。

假设我有以下模型

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

如何获得最大的年龄?

int maxAge = context.Persons.?

Answers:


152

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

并确保您using System.Linq;位于文件的顶部


2
我对此有点挣扎,因为我错过了“使用System.Linq;”。您应该考虑将该信息添加到像我这样的新手的答案中:)
RagnaRock

2
没问题@RagnaRock
krolik

3
但是,如果您没有任何记录并且EF引发错误,该怎么办。我的附加变量模型= db.BillOfLading.Select(x => x.No).LastOrDefault(); if(model!= null){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 '17

4
但是它将从数据库中检索所有列值,并将Max应用于应用程序端。
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,那么第二个答案就很好。
Deepak Sharma

2

VB.Net

Dim maxAge As Integer = context.Persons.Max(Function(p) p.Age)

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

选定的答案将引发异常,并且Carlos Toledo的答案将在从数据库中检索所有值之后应用过滤。

以下代码运行一次往返并使用任何可能的索引读取一个值,没有例外。

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.