2013-05-13 58 views
72

我的產品的集合的Linq:的GroupBy,和與計數

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到組通過產品代碼,然後我計算之和也算對每個產品代碼的記錄數。

這是我到目前爲止有:

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) 

產品1:應只列出一次... 對於上述可在引擎收錄中發現的代碼:http://pastebin.com/cNHTBSie

回答

167

我不明白的地方,第一是從哪裏來的,但在控制檯應用程序的問題是,你正在使用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,則會得到相同的結果。

我也建議你應該改變QuantityPrice性質是intdecimal類型分別爲 - 爲什麼使用這顯然不是文本數據的字符串屬性?

+0

好我的控制檯應用程序工作。感謝指出我使用First()並省略了SelectMany。 ResultLine實際上是一個ViewModel。價格將被格式化爲貨幣符號。這就是爲什麼我需要它是一個字符串。但我可以改變數量爲int ..現在我會看到,如果這也可以幫助我的網站。我會告訴你。 – ThdK 2013-05-13 13:14:46

+5

@ThdK:不,你應該保留'Price'作爲一個十進制數,然後改變你的格式。保持數據表示的清晰,並且只在最後時刻更改爲演示文稿視圖。 – 2013-05-13 13:15:48

+4

爲什麼不按產品代碼和名稱進行分組?類似這樣的:.GroupBy(l => new {l.ProductCode,l.Name})並使用ProductName = c.Key.Name, – 2013-05-13 13:23:47

13

以下查詢有效。它使用每個組進行選擇而不是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(), 
       };