2013-05-13 1 views
72

Ben bir ürün koleksiyonuna sahipLinq: GroupBy, Sum ve Kont

Şimdi ürün koduna göre grubuna koleksiyonu istiyor ve her kod için isim, numara veya ürünleri içeren bir nesne döndürür
public class Product { 

    public Product() { } 

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

ve her ürün için toplam fiyat.

public class ResultLine{ 

    public ResultLine() { } 

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

Yani o zaman toplamını hesaplamak ve ayrıca her ürün kodu için kayıtların sayısını saymak, ProductCode tarafından gruba GroupBy kullanın.

Nedense
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>(); 

, toplamı doğru yapılır ancak sayım hep 1.

sampe veridir:

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" }); 

Bu

Bugüne kadar ne var

Örnek veriler ile sonuç:

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

Ürün 1 sayısı = 2!

basit bir konsol uygulamasında bu taklit etmeye çalıştı ama aşağıdaki sonucu var:

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

Ürün1: Sadece ... bir kere listelenmiş olmalıdır Yukarıdaki pastebin bulunabilir için kodu : http://pastebin.com/cNHTBSie

cevap

167

anlamıyorum nerede birinci geliyor, ancak konsol uygulamasında sorun her gruptaki yılında her öğeyi bakmak için SelectMany kullandığınız olmasıdır "örnek veri ile sonuçlanır".

Ben sadece istediğiniz düşünüyorum:

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(); 

burada First() kullanılması ürün adı aynı ürün kodu bulunan her ürünün aynı ürün adı olduğunu varsayar olsun. Yorumlarda belirtildiği gibi, ürün adının yanı sıra ürün koduna göre gruplandırabilirsiniz. Bu, aynı kodları her zaman verilen kodlar için aynıysa, ancak EF'de daha iyi SQL üretirse aynı sonuçları verirsiniz. açıkça metinsel olmayan veriler için bir dize özelliğini kullanmak neden -

Ben de Quantity ve Price özellikleri sırasıyla int ve decimal tip olmak değiştirmesi gerektiğine öneririm?

+0

Tamam Benim konsol uygulaması çalışıyor. First() kullanmak ve SelectMany'i dışarıda bırakmak için teşekkürler. ResultLine aslında bir ViewModel'dir.Fiyat, para birimi işaretiyle biçimlendirilecek. Bu yüzden dizgiye ihtiyacım var. Ama miktarını int olarak değiştirebilirim .. Eğer web sitem için de yardımcı olabilirse şimdi göreceğim. Seni bilgilendirecegim. – ThdK

+5

@ThdK: Hayır, 'Price'ı bir ondalık olarak tutmalı ve sonra nasıl biçimlendirdiğinizi değiştirmelisiniz. Veri temsilini temiz tutun ve sadece mümkün olan en son bir sunum görünümüne geçin. –

+4

Neden ProductCode ve İsimle Gruplandırılmıyor? Bunun gibi bir şey: .GroupBy (l => new {l.ProductCode, l.Name}) ve ProductName kullanın = c.Key.Name, –

13

Aşağıdaki sorgu çalışıyor. Her grubu SelectMany yerine seçim yapmak için kullanır. SelectMany, her koleksiyondaki her öğe üzerinde çalışır. Örneğin, sorgunuzda 2 koleksiyonunuz var. SelectMany, tüm koleksiyonların yerine toplamda 3 sonuç alır. Aşağıdaki kod, toplu işlemlerinizi doğru şekilde çalışmasını sağlamak için seçim bölümünde her bir IGrouping üzerinde çalışır.

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(), 
       };