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议你应该将Quantity
和Price
属性分别更改为int
和decimal
types – 为什么使用显式不是文本的数据的string属性?
以下查询工作。 它使用每个组来执行Select而不是SelectMany
。 SelectMany
适用于每个集合的每个元素。 例如,在您的查询中,您有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(), };