在 Entity Framework ASP.NET MVC 中的 LINQ-to-Entities 中构造查询
Construct queries in LINQ-to-Entities in Entity Framework ASP.NET MVC
我很难创建满足我要求的 LINQ-to-Entities 查询。
我有两个表:Booking 和 ProcessStatusLog
预订Table:
- PNNumber (PK)
- 账户名
ProcessStatusLog Table:
- 身份证(PK)
- PNNumber (FK)
- 保险代码
- 状态
- 更新时间
以下是这些表的示例数据:
预订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
模型有一个名为 ProcessStatusLogs
的 ProcessStatusLog
对象列表,它应该看起来像这样:
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
、 的日志列表
- 从该筛选列表中获取给定
PNNumber
的 InsuranceCode
列表以及该 PNNumber
和 InsuranceCode
[= 的任何日志的最新日期37=]
- 加入结果(
InsuranceCode
、UpdatedOn
、Max(UpdatedOn)
的列表
- 从该联接 select 仅
UpdatedOn == Max(UpdatedOn)
的行(给定 PNNumber
的所有 InsuranceCode
的最新实体)
- select
Status
es
- 加入他们。
我很难创建满足我要求的 LINQ-to-Entities 查询。
我有两个表:Booking 和 ProcessStatusLog
预订Table:
- PNNumber (PK)
- 账户名
ProcessStatusLog Table:
- 身份证(PK)
- PNNumber (FK)
- 保险代码
- 状态
- 更新时间
以下是这些表的示例数据:
预订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
模型有一个名为 ProcessStatusLogs
的 ProcessStatusLog
对象列表,它应该看起来像这样:
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
、 的日志列表
- 从该筛选列表中获取给定
PNNumber
的InsuranceCode
列表以及该PNNumber
和InsuranceCode
[= 的任何日志的最新日期37=] - 加入结果(
InsuranceCode
、UpdatedOn
、Max(UpdatedOn)
的列表
- 从该联接 select 仅
UpdatedOn == Max(UpdatedOn)
的行(给定PNNumber
的所有InsuranceCode
的最新实体) - select
Status
es - 加入他们。