【问题标题】:LINQ Sum Nested collection with GroupBy and OrderByDescending使用 GroupBy 和 OrderByDescending 的 LINQ Sum 嵌套集合
【发布时间】:2012-08-21 05:44:53
【问题描述】:

我有:

public class Order
{
    public string Customer;
    public List<OrderLine> OrderLines;
}

public class OrderLine
{
    public decimal Quantity;
    public decimal UnitPrice;
}

我的目标是按金额降序搜索客户订单列表。 (金额==每个订单行的添加数量*单价)

假设我们有 2 个客户(客户 1、客户 2)的 6 个订单。每个客户有 3 个订单行。

我正在尝试:

var result = Database.GetAllOrders().OrderByDescending(order =>  
          order.Lines.Sum(ol=>ol.Quantity*ol.UnitPrice))
         .GroupBy(order=>order.CustomerName, 
         order=>order.Lines.Sum(ol=>ol.Quantity*ol.UnitPrice),
            (customerName, amount) => new {Customer=customerName, Amount=amount});

但我得到了这样的东西:

客户2:
- 数量:78
- 数量:89
- 数量:12

客户 1:
- 数量:64
- 数量:36
- 数量:28

当我试图寻找的是:

客户2:
- 金额 179

客户 1:
- 金额 128

有什么建议吗?
非常感谢!

【问题讨论】:

  • 您的代码对我来说工作正常。

标签: c# linq group-by


【解决方案1】:

听起来您需要在订购前进行分组和求和,并且只按客户名称(或理想情况下,客户 ID)分组:

var query = Database.GetAllOrders()
                    .GroupBy(order => order.CustomerName)
                    .Select(orders => new { 
                        Customer = orders.Key,
                        Amount = orders.Sum(o => o.OrderLines.Sum(
                                                 l => l.Quantity * l.UnitPrice))
                    })
                    .OrderByDescending(x => x.Amount);

【讨论】:

    【解决方案2】:

    Jon 的回答是正确的,但是如果您打算使用这个Amount 属性来排序结果并显示,那么为什么不将它变成一个具体的属性呢?

    public class Order
    {
        public string Customer;
        public List<OrderLine> OrderLines;
        public decimal Amount
        {
            get
            {
                if (this.OrderLines == null)
                    return 0;
    
                return this.OrderLines.Sum(o => o.Quantity * o.UnitPrice);
            }
        }
    }
    

    您仍在动态计算它,但如果您使用它来订购收藏品,然后想要展示它,您很可能还想将它用于其他用途 - 将其保留为访问属性。

    这就是我们拥有属性的原因!


    要真正回答这个问题,

    var result = orders
        .GroupBy(o => o.CustomerName)
        .Select(g => new
        {
            CustomerName = g.Key,
            TotalAmount = g.Sum(o => o.Amount)
        })
        .OrderByDescending(g => g.TotalAmount));
    

    【讨论】:

    • 如果您使用的是 LINQ to Objects,那很好 - 但如果这些确实是数据库中的实体,并且您希望所有的求和发生在 在 SQL 中,那将无法正常工作.当然,我们可能不会真的拥有List&lt;...&gt;。这将取决于我们是否获得了确切的真实代码或伪代码......
    【解决方案3】:

    我知道这不是一个具体的答案,但我遇到了一个类似的挑战并这样做了:

    var elements = db.Orderheads
    .Where(o => o.OrderDate.Value >= start && o.OrderDate.Value <= end)
    .GroupBy(o => o.Employee)
    .Select(g => new 
    {
        Employee = g.Key,
        OrdersCount = g.Count(),
        TotalAmount = g.Sum(o => o.TotalExVat),
        TotalQuantity = g.SelectMany(o => o.Orderlines).Sum(ol => ol.QuantityOrdered)
    })
    .OrderByDescending(o => o.TotalAmount)
    

    【讨论】:

      猜你喜欢
      • 2016-06-17
      • 1970-01-01
      • 2019-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多