วิธีรับค่าสูงสุดของคอลัมน์โดยใช้ 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 เพิ่มเติมของฉัน = db.BillOfLading.Select (x => x.No) .LastOrDefault (); ถ้า (model! = null) {var val = db.BillOfLading.Max (x => x.No);
HerGiz

มีประสิทธิภาพหรือไม่ หรือจะดีกว่าถ้าให้เอนทิตีเฟรมเวิร์กเรียกใช้โพรซีเดอร์ที่เก็บไว้ซึ่งใช้ฟังก์ชัน Max? ใหม่สำหรับกรอบงานเอนทิตีและฉันอยากรู้อยากเห็นอย่างแท้จริง
TemporaryFix

@Programmatic ไม่มีเหตุผลใดที่จะมีประสิทธิภาพมากขึ้น ยกเว้นเวอร์ชันเซิร์ฟเวอร์ Sql <= 7
mxmissile

49

หากรายการว่างเปล่าฉันจะได้รับข้อยกเว้น โซลูชันนี้จะคำนึงถึงปัญหานี้:

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

7
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ไป - กลับเซิร์ฟเวอร์เพียงครั้งเดียวและไม่มีข้อยกเว้น
9Rune5

4
แต่จะดึงค่าคอลัมน์ทั้งหมดจากฐานข้อมูลและใช้ Max ที่ฝั่งแอ็พพลิเคชัน
SuperDuck

1
สิ่งนี้ทำให้ 3 แบบสอบถามย่อย ฉันเสนอคำตอบที่แตกต่างออกไป
jsgoupil

3
เพียงแค่บันทึกด้านข้าง - ใช้ไม่ได้กับ EF core ฉันใช้:await _context.Persons.MaxAsync(x => (int?)x.Age) ?? 0
egmfrs


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;
ล่ะ

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 ก็ดี
Deepak Sharma


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();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.