Mam kolekcję produktów
public class Product {
public Product() { }
public string ProductCode {get; set;}
public decimal Price {get; set; }
public string Name {get; set;}
}
Teraz chcę pogrupować kolekcję na podstawie kodu produktu i zwrócić obiekt zawierający nazwę, liczbę lub produkty dla każdego kodu i całkowitą cenę dla każdego produktu.
public class ResultLine{
public ResultLine() { }
public string ProductName {get; set;}
public string Price {get; set; }
public string Quantity {get; set;}
}
Więc używam GroupBy do grupowania według ProductCode, a następnie obliczam sumę i liczę liczbę rekordów dla każdego kodu produktu.
Oto, co mam do tej pory:
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>();
Z jakiegoś powodu suma jest wykonywana poprawnie, ale liczba zawsze wynosi 1.
Dane 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" });
Wynik z przykładowymi danymi:
Product1: count 1 - Price:13 (2x6.5)
Product2: count 1 - Price:12 (1x12)
Produkt 1 powinien mieć liczbę = 2!
Próbowałem to zasymulować w prostej aplikacji konsolowej, ale otrzymałem następujący wynik:
Product1: count 2 - Price:13 (2x6.5)
Product1: count 2 - Price:13 (2x6.5)
Product2: count 1 - Price:12 (1x12)
Produkt1: powinien być wymieniony tylko raz ... Kod powyższego można znaleźć na pastebin: http://pastebin.com/cNHTBSie
Price
jako ułamek dziesiętny, a następnie zmienić sposób jego formatowania. Utrzymuj czystość reprezentacji danych i zmieniaj widok na prezentację tylko w ostatniej możliwej chwili.Następujące zapytanie działa. Używa każdej grupy do dokonania wyboru zamiast
SelectMany
.SelectMany
działa na każdym elemencie z każdej kolekcji. Na przykład w zapytaniu masz wynik 2 kolekcji.SelectMany
pobiera wszystkie wyniki, łącznie 3, zamiast każdego zbioru. Poniższy kod działa na każdymIGrouping
z wybranych fragmentów, aby zapewnić prawidłowe działanie operacji agregujących.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(), };
źródło
czasami musisz wybrać niektóre pola
FirstOrDefault()
lubsingleOrDefault()
możesz użyć poniższego zapytania: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();
źródło
FirstOrDefault() or
singleOrDefault () `?