Group by - List<List<T>>

0

Cześć, mam taki kawałek kodu z LINQ:

        public void GetShoppingList()
        {
            var dayIds = new List<int>() { 33, 44, 46 };
            var allProducts = (from dd in dbContext.DayDiets
                        select new { dd.Id } into day
                        join ddm in dbContext.DayDietMeals on day.Id equals ddm.DietDayId
                        join mp in dbContext.MealProducts on ddm.MealId equals mp.MealId
                        select new { mp.ProductId, mp.Quantity, day.Id } into pid
                        join p in dbContext.Products on pid.ProductId equals p.Id
                        select new { pid.Id, p.ProductName, p.CategoryId, pid.ProductId, pid.Quantity } into data
                        join c in dbContext.ProductCategories on data.CategoryId equals c.Id
                        select new {data.Id, data.ProductId, data.ProductName, data.CategoryId, data.Quantity, c.Name})
                        .ToList();

            var shoppingList = allProducts
                .Where(a => dayIds.Contains(a.Id))
                .GroupBy(a => new { Category = a.CategoryId })
                .Select(groupCat => new
                {
                    Categories = groupCat.Key,
                    Products = groupCat.GroupBy(a => a.ProductId)
                                         .Select(groupProd => new
                                         {
                                             Product = groupProd.Key,
                                             Quantity = groupProd.Sum(a => a.Quantity)
                                         }).ToList()
                }).ToList();
        }

Chciałem uzyskać obiekt pogrupowany wg kategorii, a w liście tych kategorii uzyskać listę produktów z ilością i to się po części udało:
screenshot-20210127170919.png

Jak widać mam zwrócone Id, nie wiem niestety jak odwołać się do data.ProductName oraz c.Name z obiektu allProducts tak aby wyrzucić już gotowy obiekt z nazwami. Prośba o pomoc

0

Jeżeli pogrupowałeś po ProductId, to w następnym Selekcie operujesz na kolekcji (IGruping, in fact.), a nie konkretnym produkcie, więc data.ProductName masz dostępny tak, jak Sum(a => a.Quantity)

Jak chcesz, aby wyglądał wynik?

0

@Krispekowy:

A tak?

.Select(grp => new
{
	ProductId = grp.Key,
	CategoryName = grp.First().CategoryName, // jeżeli zgrupowaliśmy po kategorii wcześniej, no to powinno być wszędzie to samo, czyż nie? 
	ProductName = grp.First().ProductName, // jeżeli zgrupowaliśmy po product id, to wszędzie jest ten sam name? 
	SumQuantities = grp.Sum(x => x.Quantity)
})
0

@WeiXiao: chciałbym osiągnąć taki obiekt końcowy:
List<ShoppingList> ShoppingList, gdzie ShoppingList składa się z:

public string categoryName {get;set;}
public List<ProductsQuantity> ProductsQuantity {get;set;}

Natomiast ProductsQuantity:

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

To co wskazałeś wyżej zwróci mi prawdopodbnie jedną listę, a ja mam tam gruping najpierw po CategoryId, a następnie po ProductId, gdzie sumuję Qantity per produkt.

screenshot-20210127184135.png

2
var data = new List<MyClass>
{
	new MyClass
	{
		Id = 1,
		CategoryId = 1,
		CategoryName = "TestCategory",
		ProductId = 1,
		ProductName = "Test",
		Quantity = 15,
    },
	new MyClass
	{
		Id = 2,
		CategoryId = 1,
		CategoryName = "TestCategory",
		ProductId = 1,
		ProductName = "Test",
		Quantity = 30,
    },
};

var list = data
.GroupBy(x => x.CategoryId)
.Select(x => new
{
	CategoryName = x.First().CategoryName,
	ProductQuantities = x
	.GroupBy(p => p.ProductId)
	.Select(p => new
	{
		ProductName = p.First().ProductName,
		Quantity = p.Sum(w => w.Quantity)
	}).ToList()
})
.ToList();

screenshot-20210127184530.png

0

@WeiXiao: wracam do tematu tego zapytania, chciałbym przemnożyć wartość "Quantity" dla każdego produktu o wartość jaką podano w tym obiekcie dla każdego dnia:

    public class ShoppingDayDTO
    {
        public int DayId { get; set; }
        public int NumberOfDays { get; set; }
    }

Czyli np. user wybrał dzień o Id 1 i podał jego ilość 3. Tzn, że dla dnia o takim id, trzeba przemnożyć wartość quantity wszystkich produktów należących do tego dnia o 3. Jak to powinno wyglądać w LINQ? Mam teraz takie zapytanie:

        public List<ShoppingListDTO> GetShoppingList(List<ShoppingDayDTO> shoppingDays)
        {
            var allProducts = (from dd in dbContext.DayDiets
                        select new { dd.Id } into day
                        join ddm in dbContext.DayDietMeals on day.Id equals ddm.DietDayId
                        join mp in dbContext.MealProducts on ddm.MealId equals mp.MealId
                        select new { mp.ProductId, mp.Quantity, day.Id } into pid
                        join p in dbContext.Products on pid.ProductId equals p.Id
                        select new { pid.Id, p.ProductName, p.CategoryId, pid.ProductId, pid.Quantity } into data
                        join c in dbContext.ProductCategories on data.CategoryId equals c.Id
                        select new {data.Id, data.ProductId, data.ProductName, data.CategoryId, data.Quantity, c.Name})
                        .ToList();

            var shoppingList = allProducts
                .Where(a => shoppingDays.Select(b=>b.DayId).Contains(a.Id))
                .GroupBy(a => new { Category = a.CategoryId })
                .Select(grpCat => new ShoppingListDTO()
                {
                    Category = grpCat.First().Name,
                    Products = grpCat
                    .GroupBy(p=>p.ProductId)
                    .Select(p=> new ProductsToBuyDTO()
                    {
                        Product = p.First().ProductName,
                        Quantity = (int)p.Sum(q => q.Quantity)
                    })
                    .ToList()
                }).ToList();
            return shoppingList;
        }

1 użytkowników online, w tym zalogowanych: 0, gości: 1