在 Entity Framework ASP.NET MVC 中的 LINQ-to-Entities 中构造查询

Construct queries in LINQ-to-Entities in Entity Framework ASP.NET MVC

我很难创建满足我要求的 LINQ-to-Entities 查询。

我有两个表:BookingProcessStatusLog

预订Table:

ProcessStatusLog Table:

以下是这些表的示例数据:

预订Table

|----------|----------------|
| PNNumber | Account Name   |
|----------|----------------|
| 11111    | Boston Celtics |
|----------|----------------|
| 22222    | Miami Heat     |
|----------|----------------|

ProcessStatusLog Table

|------|-----------|---------------|--------------|-------------|
| ID   | PNNumber  | InsuranceCode | Status       | UpdatedOn   |
|------|-----------|---------------|--------------|-------------|
| 1    | 11111     | FIRE          | NEW          | 02/22/2020  |
|------|-----------|---------------|--------------|-------------|
| 2    | 11111     | FIRE          | FOR REVIEW   | 02/23/2020  |
|------|-----------|---------------|--------------|-------------|
| 3    | 22222     | FIRE          | NEW          | 02/24/2020  |
|------|-----------|---------------|--------------|-------------|
| 4    | 22222     | MORTGAGE      | NEW          | 02/25/2020  |
|------|-----------|---------------|--------------|-------------|
| 5    | 22222     | MORTGAGE      | FOR REVIEW   | 02/26/2020  |
|------|-----------|---------------|--------------|-------------|
| 6    | 22222     | FIRE          | CANCELLED    | 02/28/2020  |
|------|-----------|---------------|--------------|-------------|

现在,我想获取每个保险代码的单个 PN 的最新状态。

例如: 我想获得 PNNumber 11111 的最新状态。我想获得的输出是 "FOR REVIEW".

对于 PNNumber 22222,所需的输出将是 "FOR REVIEW, CANCELLED"

如何为此编写 EF 查询? 谢谢

我不知道它是否会直接转换为 SQL 或者您需要先获取整个列表,但是您应该可以通过使用 [GroupBy][1] 方法来实现。

假设您的 Booking 模型有一个名为 ProcessStatusLogsProcessStatusLog 对象列表,它应该看起来像这样:

var result = bookings.GroupBy(
  x => x.Id,
  (_, g) => g.SelectMany(x => x.ProcessStatusLogs)
             .OrderByDescending(x => x.UpdatedOn)
             .FirstOrDefault()
);

重新创建数据库:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Booking>().HasKey(b => b.PNNumber);
    modelBuilder.Entity<Booking>().HasData(
        new Booking { PNNumber = "11111", AccountName = "Boston Celtics" },
        new Booking { PNNumber = "22222", AccountName = "Miami Heat" });

    modelBuilder.Entity<ProcessStatusLog>().HasData(
        new ProcessStatusLog { ID = 1, PNNumber = "11111", InsuranceCode = "FIRE", Status = "NEW", UpdatedOn = DateTime.Parse("22/02/2020") },
        new ProcessStatusLog { ID = 2, PNNumber = "11111", InsuranceCode = "FIRE", Status = "FOR REVIEW", UpdatedOn = DateTime.Parse("23/02/2020") },
        new ProcessStatusLog { ID = 3, PNNumber = "22222", InsuranceCode = "FIRE", Status = "NEW", UpdatedOn = DateTime.Parse("24/02/2020") },
        new ProcessStatusLog { ID = 4, PNNumber = "22222", InsuranceCode = "MORTGAGE", Status = "NEW", UpdatedOn = DateTime.Parse("25/02/2020") },
        new ProcessStatusLog { ID = 5, PNNumber = "22222", InsuranceCode = "MORTGAGE", Status = "FOR REVIEW", UpdatedOn = DateTime.Parse("26/02/2020") },
        new ProcessStatusLog { ID = 6, PNNumber = "22222", InsuranceCode = "FIRE", Status = "CANCELLED", UpdatedOn = DateTime.Parse("28/02/2020") });

    base.OnModelCreating(modelBuilder);
}

查询:

public IActionResult Index()
{
    this.dbContext.Database.EnsureCreated();

    string givenPNNumber = "22222";

    var filteredLogs = dbContext.ProcessStatusLog
        .Where(log => log.PNNumber == givenPNNumber);

    // Get date of the latest log for each incurance code for eaxh PNNumber.
    var groupedLogs = filteredLogs
        .GroupBy(psl => psl.InsuranceCode)
        .Select(group => new
        {
            Code = group.Key,
            LastUpdate = group.Max(g => g.UpdatedOn)
        });

    var result =
        from logs in filteredLogs
        join latestLogs in groupedLogs 
            on logs.InsuranceCode equals latestLogs.Code into joined
        from j in joined.DefaultIfEmpty()
        where logs.UpdatedOn == j.LastUpdate
        select logs.Status;

    string finalResult = string.Join(',', result.ToList());
    return View();
}

因为我只使用内存中的 Db,所以我不知道 EF 将如何生成查询,但查询计划是:

  • 仅获取给定 PNNumber
  • 的日志列表
  • 从该筛选列表中获取给定 PNNumberInsuranceCode 列表以及该 PNNumberInsuranceCode[= 的任何日志的最新日期37=]
  • 加入结果(InsuranceCodeUpdatedOnMax(UpdatedOn)
  • 的列表
  • 从该联接 select 仅 UpdatedOn == Max(UpdatedOn) 的行(给定 PNNumber 的所有 InsuranceCode 的最新实体)
  • select Statuses
  • 加入他们。