Имя: Пароль:
1C
1С v8
Разузлование: контроль зацикливания в дереве узлов
0 UtkinPavel
 
22.11.11
19:47
В университете задали решать задачу, связанную с разузлованием. В рамках этой задачи решить проблему зацикливания в дереве узлов.

Дано

два справочника "Номенклатура" и "Спецификации". "Номенклатура" - простой справочник без реквизитов, групп, владельцев/подчиненных. "спецификации" - простой справочник с реквизитом "СборочнаяЕдиница" (СправочникСсылка.Номенклатура) и табличной частью "ТЧ" с реквизитами "Компонента" (СправочникСсылка.Номенклатура) и "Количество" (Число).
Платформа: 1С 8.2.14.528.

Ниже приведено мое решение.

Вопрос: существует ли более правильное и менее затратное решение, чем мое?

Мое решение

Я решил контролировать зацикливание на стадии создания нового элемента в справочнике "Спецификации". Процедура проверки вызывается в процедуре "ПередЗаписью()".

а. проблема "А - А" (компонента входит саму в себя) мной решена так. Сначала пользователь вводит сборочную единицу. После ввода это поле блокируется, разблокировывается табличная часть. При выборе компоненты в динамический список формы выбора номенклатуры передается параметр со значением выбранной сборочной единицы - соответственно динамический список формируется без нее.

б. проблема "А - ... - А" (компонента входит саму в себя опосредованно) мной решена так. Формируется таблица значений с колонками "сборочная единица" и "компонента". Сначала с помощью разузлования снизу-вверх формируется ветвь узлов, являющихся сборочными единицами для выбранной сборочной единицы и ее сборочных единиц вплоть до самой верхней. Комбинации заносятся в ТЗ. Затем каждый из добавленных в ТЗ компонент разузловывается и комбинации снова заносятся в ТЗ. После этого ТЗ проверяется на наличие повторяющихся записей. Если таковые имеются - значит есть зацикливание.

Код:
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
   
   Объект.Наименование = Строка(Объект.СборочнаяЕдиница);
   
   Отказ = ПроверитьЗацикливание();
   
КонецПроцедуры



&НаСервере
Функция ПроверитьЗацикливание()
   
   ///////////////////////////
   //Построение дерева узлов//
   ///////////////////////////
   
   Дерево = Новый ТаблицаЗначений;
   Дерево.Колонки.Добавить("СборочнаяЕдиница");
   Дерево.Колонки.Добавить("Компонента");
   
   ОбратноеРазузлование(Объект.СборочнаяЕдиница, Дерево);
   
   Для Каждого ТекущаяСтрока Из Объект.ТЧ Цикл
       
       НоваяСтрока = Дерево.Добавить();
       НоваяСтрока.СборочнаяЕдиница = Объект.СборочнаяЕдиница;
       НоваяСтрока.Компонента = ТекущаяСтрока.Компонента;
       
       ПрямоеРазузлование(Дерево, ТекущаяСтрока.Компонента);
       
   КонецЦикла;
   
   ////////////////////////////////////////////////
   //Проверка наличия зацикливаний в дереве узлов//
   ////////////////////////////////////////////////
   
   КоличествоОшибок = 0;
   
   Для Каждого ТекущаяСтрока Из Дерево Цикл
       
       Массив = Дерево.НайтиСтроки(Новый Структура("СборочнаяЕдиница, Компонента", ТекущаяСтрока.СборочнаяЕдиница, ТекущаяСтрока.Компонента));
       
       КоличествоОшибок = КоличествоОшибок + Массив.Количество() - 1;                
       
   КонецЦикла;
   
   //////////////////////
   //Возврат результата//
   //////////////////////
   
   Если КоличествоОшибок = 0 Тогда
       
       Возврат Ложь;
       
   Иначе
       
       Сообщить("Обнаружена угроза зацикливания! Пожалуйста, внесите изменения в список компонент.");
       
       Возврат Истина;
       
   КонецЕсли;
   
КонецФункции



&НаСервере
Процедура ПрямоеРазузлование(Дерево, Узел)
   
   Запрос = Новый Запрос
   (
       "ВЫБРАТЬ
       |    СпецификацииТЧ.Компонента КАК Компонента
       |ИЗ
       |    Справочник.Спецификации.ТЧ КАК СпецификацииТЧ
       |        ПОЛНОЕ СОЕДИНЕНИЕ Справочник.Спецификации КАК Спецификации
       |        ПО СпецификацииТЧ.Ссылка = Спецификации.Ссылка
       |ГДЕ
       |    Спецификации.СборочнаяЕдиница = &СборочнаяЕдиница"
   );

   Запрос.УстановитьПараметр("СборочнаяЕдиница", Узел);

   Результат = Запрос.Выполнить().Выбрать();

   Пока Результат.Следующий() Цикл
       
       НоваяСтрока                        = Дерево.Добавить();
       НоваяСтрока.СборочнаяЕдиница    = Узел;
       НоваяСтрока.Компонента            = Результат.Компонента;
       
       ПрямоеРазузлование(Дерево, Результат.Компонента);
       
   КонецЦикла;

КонецПроцедуры



&НаСервере
Процедура ОбратноеРазузлование(Узел, Дерево)
   
   Запрос = Новый Запрос
   (
       "ВЫБРАТЬ
       |    Спецификации.СборочнаяЕдиница КАК СборочнаяЕдиница
       |ИЗ
       |    Справочник.Спецификации.ТЧ КАК СпецификацииТЧ
       |        ПОЛНОЕ СОЕДИНЕНИЕ Справочник.Спецификации КАК Спецификации
       |        ПО СпецификацииТЧ.Ссылка = Спецификации.Ссылка
       |ГДЕ
       |    СпецификацииТЧ.Компонента = &Компонента"
   );
   
   Запрос.УстановитьПараметр("Компонента", Узел);
   
   Результат = Запрос.Выполнить().Выбрать();

   Пока Результат.Следующий() Цикл
       
       НоваяСтрока = Дерево.Добавить();
       НоваяСтрока.СборочнаяЕдиница = Результат.СборочнаяЕдиница;
       НоваяСтрока.Компонента = Узел;
       
       ОбратноеРазузлование(Результат.СборочнаяЕдиница, Дерево);
       
   КонецЦикла;    

КонецПроцедуры
1 Базис
 
naïve
22.11.11
19:50
Это где сейчас так учат?
2 Михаил Козлов
 
22.11.11
19:53
Можно разузловывать не до конца, проверяя при разузловании компоненты вхождение ее компонент в "текущий" список компонент.
3 UtkinPavel
 
22.11.11
20:18
"Базис

Это где сейчас так учат?"

ННГУ.
Пожалуйста, ругайте, критикуйте, советуйте — все приму во внимание.
4 UtkinPavel
 
22.11.11
20:23
Михаил Козлов: "Можно разузловывать не до конца, проверяя при разузловании компоненты вхождение ее компонент в "текущий" список компонент."

Спасибо!
5 Armando
 
22.11.11
20:43