Làm cách nào để nhận giá trị tối đa của một cột bằng Entity Framework?


92

Để nhận giá trị lớn nhất của một cột chứa số nguyên, tôi có thể sử dụng kết hợp T-SQL sau

SELECT MAX(expression )
FROM tables
WHERE predicates;

Có thể đạt được kết quả tương tự với Entity Framework không.

Giả sử tôi có mô hình sau

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

Làm thế nào để lấy được tuổi của người lớn nhất?

int maxAge = context.Persons.?

Câu trả lời:


152

Thử đi int maxAge = context.Persons.Max(p => p.Age);

Và đảm bảo rằng bạn có using System.Linq;ở đầu tệp của mình


2
Tôi bối rối một chút với điều này vì tôi đã bỏ lỡ "using System.Linq;" Bạn nên cân nhắc thêm rằng thông tin để trả lời của bạn để người mới như tôi :)
RagnaRock

2
Không thành vấn đề @RagnaRock
krolik

3
Nhưng điều gì sẽ xảy ra nếu bạn không có bất kỳ bản ghi nào và lỗi ném EF. Bổ sung của tôi var model = db.BillOfLading.Select (x => x.No) .LastOrDefault (); if (model! = null) {var val = db.BillOfLading.Max (x => x.No);
HerGiz

Điều này có hiệu quả không? Hay sẽ tốt hơn nếu khung thực thể thực thi một thủ tục được lưu trữ sử dụng hàm Max? Mới đối với khung thực thể và tôi thực sự tò mò
Tạm thời, Thứ

@Programmatic hoàn toàn không có lý do gì hiệu quả hơn. Ngoại trừ trên phiên bản Máy chủ Sql <= 7.
mxmissile

49

Nếu danh sách trống, tôi nhận được một ngoại lệ. Giải pháp này sẽ tính đến vấn đề này:

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

7
Đây phải là câu trả lời được chấp nhận. Chỉ một chuyến khứ hồi đến máy chủ và không có ngoại lệ.
9

4
Nhưng nó lấy tất cả các giá trị cột từ cơ sở dữ liệu và áp dụng Max ở phía ứng dụng.
SuperDuck

1
Điều này tạo ra 3 truy vấn phụ. Tôi đã đề xuất một câu trả lời khác.
jsgoupil

3
chỉ là một lưu ý phụ - điều này không hoạt động với lõi EF. Tôi đã sử dụng:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs

11

Hoặc bạn có thể thử cách này:

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

7

Có thể giúp, nếu bạn muốn thêm một số bộ lọc:

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

4
maxAge = Persons.Max(c => c.age)

Hoặc một cái gì đó dọc theo các đường dây.


4

Cột của bạn không có giá trị

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

Cột của bạn không thể nullable

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

Trong cả hai trường hợp, bạn có thể sử dụng mã thứ hai. Nếu bạn sử dụng DefaultIfEmpty, bạn sẽ thực hiện một truy vấn lớn hơn trên máy chủ của mình. Đối với những người quan tâm, đây là EF6 tương đương:

Truy vấn không có DefaultIfEmpty

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

Truy vấn với 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
Cònint maxAge = context.Persons.Max(x => (int?)x.Age) ?? 0;
egmfrs

3

Như nhiều người đã nói - phiên bản này

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

ném một ngoại lệ khi bảng trống.

Sử dụng

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

hoặc là

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

Câu trả lời thứ hai của bạn có vẻ tốt với tôi, nếu ai đó nhìn vào SQL được tạo, câu trả lời thứ hai là tốt.
Deepak Sharma

2

Trong VB.Net nó sẽ là

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

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

Phiên bản này, nếu danh sách trống :

  • Trả về null- đối với quá tải có thể không
  • Ném Sequence contains no elementngoại lệ - cho quá tải không thể null

-

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

Phiên bản này xử lý trường hợp danh sách trống, nhưng nó tạo ra truy vấn phức tạp hơn và vì một số lý do không hoạt động với EF Core.

-

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

Phiên bản này thanh lịch và hiệu quả (truy vấn đơn giản và một chuyến đi vòng quanh cơ sở dữ liệu), hoạt động với EF Core. Nó xử lý ngoại lệ được đề cập ở trên bằng cách truyền kiểu không thể nullable thành nullable và sau đó áp dụng giá trị mặc định bằng ??toán tử.


1

Câu trả lời đã chọn ném ra các ngoại lệ và câu trả lời từ Carlos Toledo áp dụng tính năng lọc sau khi truy xuất tất cả các giá trị từ cơ sở dữ liệu.

Cái sau chạy một chuyến khứ hồi và đọc một giá trị duy nhất, sử dụng bất kỳ chỉ mục nào có thể có, không có ngoại lệ.

int maxAge = _dbContext.Persons
  .OrderByDescending(p => p.Age)
  .Select(p => p.Age)
  .FirstOrDefault();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.