Что является более чистым или более эффективным способом перебора вложенных коллекций объектов? - PullRequest
0 голосов
/ 10 января 2019

Я работаю над созданием объекта с вложенной иерархией из сплющенного списка элементов спецификации (ведомости материалов) из SQL, которые содержат уровень спецификации и родителя, которому они принадлежат. По сути, каждый родительский элемент, представляющий собой сборку из меньших частей, должен добавлять свои части в коллекцию этого объекта. Я считаю, что у нас есть некоторые части, которые могут повторяться до 10 уровней, и мне не нравится, как работает этот шаблон.

Этот набор данных взят из хранимой процедуры, которая выполняет сложный запрос CTE, и я не заинтересован в том, чтобы пытаться заставить эту работу работать с Entity Framework, так как у нас много баз данных, и нам нужен лучший контроль над SQL, который мы пишем (отсюда и хранимая процедура). В конечном итоге это будет JSON, который я буду отображать как свернутое дерево в браузере.

Вот уродливая часть, которую я надеюсь немного почистить. Суть того, что здесь происходит, прежде чем я начну повторять различные уровни:

  1. Установить первый элемент (не полный, но это основной элемент).
  2. Выполнить хранимую процедуру (с параметром) для возврата таблицы данных.
  3. Создать плоский список объектов, которые я хочу вложить.
  4. Получите общее количество вложенных уровней, существующих в спецификации.
  5. Перебирайте все уровни очень уродливо.
public BOMItemModel GetItemBOM(string item)
        {
            try
            {
                var bom = new BOMItemModel { PLPartNumber = item, BOMLevel = 0 };
                var par = new Hashtable();
                par.Add("@Item", item);
                var dt = db.GetDataTable("[part].[getItemBOM]", par);
                var bomList = new List<BOMItemModel>();
                foreach(DataRow r in dt.Rows)
                {
                    bomList.Add(MapBomItem(r));
                }
                var bomLevels = bomList.Max(x => x.BOMLevel);
                for(var i = 1; i < bomLevels; i++)
                {
                    foreach (var b in bomList.Where(x => x.BOMLevel == i).ToList())
                    {
                        if (i == 1)
                        {
                            bom.SubItems.Add(b);
                        }
                        else
                        {
                            if (i == 2)
                            {
                                var lvl2Items = bom.SubItems;
                                var parent1 = lvl2Items.FirstOrDefault(x => x.PLPartNumber == b.ParentPLNumber);
                                if (parent1 != null) parent1.SubItems.Add(b);
                            }
                            if (i == 3)
                            {
                                var lvl2Items = bom.SubItems;
                                foreach(var lvl2 in lvl2Items)
                                {
                                    var lvl3Items = lvl2.SubItems;
                                    var parent2 = lvl3Items.FirstOrDefault(x => x.PLPartNumber == b.ParentPLNumber);
                                    if (parent2 != null) parent2.SubItems.Add(b);
                                }
                            }
                            if (i == 4)
                            {
                                var lvl2Items = bom.SubItems;
                                foreach (var lvl2 in lvl2Items)
                                {
                                    var lvl3Items = lvl2.SubItems;
                                    foreach (var lvl3 in lvl3Items)
                                    {
                                        var lvl4Items = lvl3.SubItems;
                                        var parent3 = lvl4Items.FirstOrDefault(x => x.PLPartNumber == b.ParentPLNumber);
                                        if (parent3 != null) parent3.SubItems.Add(b);
                                    }
                                }
                            }
                            if (i == 5)
                            {
                                var lvl2Items = bom.SubItems;
                                foreach (var lvl2 in lvl2Items)
                                {
                                    var lvl3Items = lvl2.SubItems;
                                    foreach (var lvl3 in lvl3Items)
                                    {
                                        var lvl4Items = lvl3.SubItems;
                                        foreach (var lvl4 in lvl4Items)
                                        {
                                            var lvl5Items = lvl4.SubItems;
                                            var parent4 = lvl5Items.FirstOrDefault(x => x.PLPartNumber == b.ParentPLNumber);
                                            if (parent4 != null) parent4.SubItems.Add(b);
                                        }
                                    }
                                }
                            }
                            if (i == 6)
                            {
                                var lvl2Items = bom.SubItems;
                                foreach (var lvl2 in lvl2Items)
                                {
                                    var lvl3Items = lvl2.SubItems;
                                    foreach (var lvl3 in lvl3Items)
                                    {
                                        var lvl4Items = lvl3.SubItems;
                                        foreach (var lvl4 in lvl4Items)
                                        {
                                            var lvl5Items = lvl4.SubItems;
                                            foreach (var lvl5 in lvl5Items)
                                            {
                                                var lvl6Items = lvl5.SubItems;
                                                var parent5 = lvl6Items.FirstOrDefault(x => x.PLPartNumber == b.ParentPLNumber);
                                                if (parent5 != null) parent5.SubItems.Add(b);
                                            }
                                        }
                                    }
                                }
                            }
                        }

                    }
                }

                return bom;
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message, ex);
            }
            return null;
        }

Вот так выглядит моя модель или класс:

public class BOMItemModel
{
    public BOMItemModel()
    {
        SubItems = new List<BOMItemModel>();
    }
   public string ParentPLNumber { get; set; }
   public string PartNumber { get; set; }
   public string PartListName { get; set; }
   public string ItemNumber { get; set; }
   public string PLPartNumber { get; set; }
   public string PartType { get; set; }
   public string PLManufacturer { get; set; }
   public string PLDescription { get; set; }
   public decimal Qty { get; set; }
   public int BOMLevel { get; set; }
   public List<BOMItemModel> SubItems { get; set; }
}

Последнее свойство этого класса - это то, где я вставляю подпункты родительского элемента, и это может вложить несколько уровней вглубь.

1 Ответ

0 голосов
/ 10 января 2019

Да, было бы намного лучше:

for (var i = 1; i <= bomLevels; i++)
                {
                    foreach (var b in bomList.Where(x => x.BOMLevel == i).ToList())
                    {
                        if (i == 1)
                        {
                            bom.SubItems.Add(b);
                        }
                        else
                        {
                            var parent = bomList.FirstOrDefault(x => x.PLPartNumber == b.ParentPLNumber && b.BOMLevel - 1 == x.BOMLevel);
                            if (parent != null) parent.SubItems.Add(b);
                        }


                    }
                }

Кроме того, я бы выдал ошибку, когда родитель не найден. Для более общего подхода взгляните на мой другой пример: Преобразование таблицы в дерево

...