162

我有一系列产品

public class Product {

   public Product() { }

   public string ProductCode {get; set;}
   public decimal Price {get; set; }
   public string Name {get; set;}
}

现在我想根据产品代码对集合进行分组,并返回一个对象,其中包含每个代码的名称、数量或产品以及每个产品的总价格。

public class ResultLine{

   public ResultLine() { }

   public string ProductName {get; set;}
   public string Price {get; set; }
   public string Quantity {get; set;}
}

所以我使用 GroupBy 按 ProductCode 分组,然后计算总和并计算每个产品代码的记录数。

这是我到目前为止所拥有的:

List<Product> Lines = LoadProducts();    
List<ResultLine> result = Lines
                .GroupBy(l => l.ProductCode)
                .SelectMany(cl => cl.Select(
                    csLine => new ResultLine
                    {
                        ProductName =csLine.Name,
                        Quantity = cl.Count().ToString(),
                        Price = cl.Sum(c => c.Price).ToString(),
                    })).ToList<ResultLine>();

由于某种原因,总和正确完成,但计数始终为 1。

样本数据:

List<CartLine> Lines = new List<CartLine>();
            Lines.Add(new CartLine() { ProductCode = "p1", Price = 6.5M, Name = "Product1" });
            Lines.Add(new CartLine() { ProductCode = "p1", Price = 6.5M, Name = "Product1" });
            Lines.Add(new CartLine() { ProductCode = "p2", Price = 12M, Name = "Product2" });

带有样本数据的结果:

Product1: count 1   - Price:13 (2x6.5)
Product2: count 1   - Price:12 (1x12)

产品 1 应该有 count = 2!

我试图在一个简单的控制台应用程序中模拟这一点,但我得到了以下结果:

Product1: count 2   - Price:13 (2x6.5)
Product1: count 2   - Price:13 (2x6.5)
Product2: count 1   - Price:12 (1x12)

Product1:应该只列出一次...上面的代码可以在pastebin上找到:http: //pastebin.com/cNHTBSie

4

3 回答 3

339

我不明白第一个“带有样本数据的结果”来自哪里,但控制台应用程序中的问题是您正在使用SelectMany来查看每个组中的每个项目

我想你只是想要:

List<ResultLine> result = Lines
    .GroupBy(l => l.ProductCode)
    .Select(cl => new ResultLine
            {
                ProductName = cl.First().Name,
                Quantity = cl.Count().ToString(),
                Price = cl.Sum(c => c.Price).ToString(),
            }).ToList();

使用First()此处获取产品名称假设具有相同产品代码的每个产品具有相同的产品名称。如评论中所述,您可以按产品名称和产品代码进行分组,如果任何给定代码的名称始终相同,则会给出相同的结果,但显然会在 EF 中生成更好的 SQL。

我还建议您应该将QuantityandPrice属性分别更改为intanddecimal类型 - 为什么对显然不是文本的数据使用字符串属性?

于 2013-05-13T13:07:08.887 回答
34

以下查询有效。它使用每个组来进行选择而不是SelectMany. SelectMany作用于每个集合中的每个元素。例如,在您的查询中,您有 2 个集合的结果。SelectMany得到所有结果,一共3个,而不是每个集合。以下代码适用于IGrouping选择部分中的每个,以使您的聚合操作正常工作。

var results = from line in Lines
              group line by line.ProductCode into g
              select new ResultLine {
                ProductName = g.First().Name,
                Price = g.Sum(pc => pc.Price).ToString(),
                Quantity = g.Count().ToString(),
              };
于 2013-05-13T13:31:44.850 回答
5

有时您需要选择一些字段,FirstOrDefault()或者singleOrDefault()您可以使用以下查询:

List<ResultLine> result = Lines
    .GroupBy(l => l.ProductCode)
    .Select(cl => new Models.ResultLine
            {
                ProductName = cl.select(x=>x.Name).FirstOrDefault(),
                Quantity = cl.Count().ToString(),
                Price = cl.Sum(c => c.Price).ToString(),
            }).ToList();
于 2019-05-14T06:27:37.477 回答