c# - 使用 EntityFramework Core 为每个客户选择支付最低的记录
问题描述
我有一个应用程序可以将客户与库存中的车辆进行匹配。有 3 个主表:Customer、Match 和 Inventory。匹配记录包含特定客户和库存记录的估计每月付款。一个客户可以与 Inventory 中的多辆汽车相匹配。
匹配记录包含一个 CustomerId 和一个 InventoryId 以及一个 MonthlyPayment 字段和一些其他杂项字段。
Customer 和 Match 之间存在一对多的关系。Inventory 和 Match 之间存在一对多的关系。
对于每个客户,我想选择客户记录、每月付款最低的匹配记录以及该匹配的库存记录。
做这个的最好方式是什么?可以通过单个查询完成吗?
我试过这段代码,但实体框架无法评估它,它会在本地执行它,这会降低性能。
var bestMatches = _matchRepository.GetAll(customerMatchSummaryRequest)
.Where(match =>
(_matchRepository.GetAll(customerMatchSummaryRequest)
.GroupBy(m => new { m.Bpid, m.BuyerId, m.CurrentVehicleId })
.Select(g => new
{
g.Key.Bpid,
g.Key.BuyerId,
g.Key.CurrentVehicleId,
LowestMonthlyPayment = g.Min(m => m.MonthlyPayment)
})
.Where(m => m.Bpid == match.Bpid
&& m.BuyerId == match.BuyerId
&& m.CurrentVehicleId == match.CurrentVehicleId
&& m.LowestMonthlyPayment == match.MonthlyPayment)
).Any())
.Include(m => m.Buyer)
.Include(m => m.Inventory);
单步执行调试器时,我收到以下输出:
Microsoft.EntityFrameworkCore.Query:Warning: The LINQ expression 'GroupBy(new <>f__AnonymousType2`3(Bpid = [<generated>_2].Bpid, BuyerId = [<generated>_2].BuyerId, CurrentVehicleId = [<generated>_2].CurrentVehicleId), [<generated>_2])' could not be translated and will be evaluated locally.
Microsoft.EntityFrameworkCore.Query:Warning: The LINQ expression 'GroupBy(new <>f__AnonymousType2`3(Bpid = [<generated>_2].Bpid, BuyerId = [<generated>_2].BuyerId, CurrentVehicleId = [<generated>_2].CurrentVehicleId), [<generated>_2])' could not be translated and will be evaluated locally.
解决方案
假设你的模型是这样的
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Match> Matches { get; set; }
}
public class Inventory
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Match> Matches { get; set; }
}
public class Match
{
public int CustomerId { get; set; }
public Customer Custmer { get; set; }
public int InventoryId { get; set; }
public Inventory Inventory { get; set; }
public decimal MonthlyPayment { get; set; }
}
有问题的查询可能是这样的:
var query =
from customer in db.Set<Customer>()
from match in customer.Matches
where !customer.Matches.Any(m => m.MonthlyPayment > match.MonthlyPayment)
select new
{
Customer = customer,
Match = match,
Inventory = match.Inventory
};
请注意,如果它包含多个最低付款的库存记录,它可能会为客户返回多个匹配项。如果数据允许,并且您希望每个客户恰好获得 0 或 1 个结果,请更改
m.MonthlyPayment > match.MonthlyPayment
标准
m.MonthlyPayment > match.MonthlyPayment ||
(m.MonthlyPayment == match.MonthlyPayment && m.InventoryId < match.InventoryId)
PS 上面的 LINQ 查询是目前转换为单个 SQL 查询的唯一方法。不幸的是,更自然的方式像
from customer in db.Set<Customer>()
let match = customer.Matches.OrderBy(m => m.MonthlyPayment).FirstOrDefault()
...
或者
from customer in db.Set<Customer>()
from match in customer.Matches.OrderBy(m => m.MonthlyPayment).Take(1)
...
导致客户评价。
推荐阅读
- xml - 使用 XSLT 将所有节点包装在 2 条处理指令之间
- c# - ArgumentException:无法转换类型的对象。但我有一个隐式运算符 C#
- http - 内容类型多参数
- python - 使用python创建地图
- swift - 在 SwiftUI 视图中一起分配属性值?
- python - Slack 不展开图像链接以显示预览图像
- object-detection-api - 使用对象检测 API 微调具有不同类数的模型
- html - W3 CSS 和正文滚动锁定
- sqlite - 如何从 UIPath 对 SQLite DB 进行 CRUD 更新
- flutter - 新状态不调用 Flutter BlocBuilder