Linq:GroupBy,Sum和Count

我有一个产品的集合

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进行分组,然后计算总和并计算每个产品代码的logging数。

这是我迄今为止:

 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。

Sampe数据:

 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上find: http : //pastebin.com/cNHTBSie

我不明白第一个“示例数据结果”是从哪里来的,但是控制台应用程序中的问题是您正在使用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。

我还build议你应该将QuantityPrice属性分别更改为intdecimaltypes – 为什么使用显式不是文本的数据的string属性?

以下查询工作。 它使用每个组来执行Select而不是SelectManySelectMany适用于每个集合的每个元素。 例如,在您的查询中,您有2个集合的结果。 SelectMany获取所有结果,共3个,而不是每个集合。 以下代码在select部分中的每个IGrouping上工作,以使您的聚合操作正常工作。

 var results = from line in Lines group line by line.ProductCode into g select new ResultLine { ProductName = g.First().Name, Price = g.Sum(_ => _.Price).ToString(), Quantity = g.Count().ToString(), };