GroupBy с сущностью linq poco - PullRequest
0 голосов
/ 29 мая 2019

У меня есть эти объекты

public class Counter
    {
        public int DocEntry { get; set; }
        public int LineId { get; set; }
        public string Item { get; set; }
        public decimal Quantity { get; set; }
        public string FromWarehouse { get; set; }
        public string ToWarehouse { get; set; }
        public virtual List<Batch> batchs { get; set; }
    }

    public class Batch
    {
      public string BatchNumber { get; set; }

        public decimal Quantity { get; set; }
    }

И у меня есть Счетчик списка, я должен сгруппировать элементы списка на основе значения Элемента, FromWarehouse, ToWarehouse, и результат должен быть сгруппирован с суммированным количеством и списком Пакетных слияний, я попытался циклически обработать список Счетчиков, используя метод foreach и вставка в новый список первого элемента, в последующих итерациях, если текущая строка отражает значения уже существующего в списке, я суммировал количества и добавлял в список «Пакет» элементы списка «Пакет» -я строка, в противном случае я добавил новую строку, этот подход мне показался слишком сложным, не очень хорошо разбираясь в linq, или в любом случае есть более простой способ управлять группой?

Это мой метод:

public static List<Counter> GroupBy(List<Counter> list)
        {
            List<Counter> rows = new List<Counter>();
            int i = 0;
            foreach (Counter elem in list)
            {
                if (list.First() == elem)
                {
                    rows.Add(elem);
                    i++;
                }
                else
                {

                    if (elem.Item == rows.ElementAt(i).Item &&
                        elem.FromWarehouse == rows.ElementAt(i).FromWarehouse &&
                        elem.ToWarehouse == rows.ElementAt(i).ToWarehouse)
                    {
                        rows.First().Quantity += elem.Quantity;
                        rows.First().batchs.Add(elem.batchs.First());
                    }
                    else
                    {
                        rows.Add(elem);
                        i++;
                    }
                }
            }

            return rows;
        }

Это решение:

public static List<Counter> GroupBy(List<Counter> list)
        {
            List<Counter> rows = new List<Counter>();

            foreach (Counter elem in list)
            {
                if (rows.Any(x=>x.Item == elem.Item &&
                        x.FromWarehouse == elem.FromWarehouse &&
                        x.ToWarehouse == elem.ToWarehouse))
                {
                    rows.First().Quantity += elem.Quantity;
                    rows.First().batchs.Add(elem.batchs.First());
                }
                else
                {
                    rows.Add(elem);
                }
            }

            return rows;
        }

1 Ответ

0 голосов
/ 29 мая 2019

Давайте попробуем написать Linq , шаг за шагом.

"У меня есть список count":

   List<Counter> count = ...

"Я должен сгруппировать элементы списка на основе значения Item, FromWarehouse, ToWarehouse":

   var result = count
     .GroupBy(item => new {
        item.Item,
        item.FromWarehouse
        item.ToWarehouse 
      })

"result следует сгруппировать с суммированным quantity и списком Batch слитых ", то есть вы должны Aggregate элементов в пределах каждого chunk

   var result = count  
     .GroupBy(item => new {
        item.Item,
        item.FromWarehouse
        item.ToWarehouse 
      })
     .Select(chunk => new {
        key = chunk.Key,
        summary = chunk.Aggregate(
          Tuple.Create(0m, new List<Batch>()),                      // initial empty
          (s, a) => Tuple.Create(s.Item1 + a.Quantity,              // add
                                 s.Item2.Concat(a.batchs).ToList()) // merge
      })

Наконец, давайте представим result в более удобном (читаемом) формате:

   var result = count  
     .GroupBy(item => new {
        item.Item,
        item.FromWarehouse
        item.ToWarehouse 
      })
     .Select(chunk => new {
        key = chunk.Key,
        summary = chunk.Aggregate(
          Tuple.Create(0m, new List<Batch>()),
          (s, a) => Tuple.Create(s.Item1 + a.Quantity, 
                                 s.Item2.Concat(a.batchs).ToList())
      })
     .Select(item => new {
        Item = item.key.Item,
        FromWarehouse = item.key.FromWarehouse,
        ToWarehouse = item.key.ToWarehouse,
        Quantity = item.summary.Item1,
        Batches = item.summary.Item2
      }); // Add ToArray() if you want to materialize
...