首页 > 解决方案 > 使用 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.

标签: c#entity-framework-core

解决方案


假设你的模型是这样的

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)
    ...

导致客户评价


推荐阅读