При работе со справочниками в системе «1С:Предприятие 8» часто возникает задача программного получения списка элементов или групп, которые находятся внутри определенного родителя. Это может быть необходимо для построения отчетов, обработки номенклатуры или автоматического заполнения документов. В этой статье мы подробно разберем, как эффективно решать подобные задачи, используя различные механизмы платформы.
Использование запросов — это наиболее правильный и производительный способ получения данных в 1С. Для того чтобы выбрать все подчиненные группы внутри конкретной папки (например, «Торговая деятельность»), нам потребуется использовать условие В ИЕРАРХИИ. Рассмотрим, чем оно отличается от обычного сравнения.
Анализируем разницу в условиях:
ГДЕ Родитель = &Параметр выберет только тех «потомков», которые находятся на первом уровне вложенности относительно родителя.ГДЕ Ссылка В ИЕРАРХИИ(&Параметр) выберет все элементы и группы на всех уровнях вложенности, фактически «спускаясь» до самого низа дерева справочника.Разберем пример кода, который выбирает только группы (папки) внутри заданной иерархии:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа = ИСТИНА
| И Номенклатура.Ссылка В ИЕРАРХИИ(&РодительскаяГруппа)";
// Сначала найдем ссылку на нашу группу «Торговая деятельность»
ГруппаСсылка = Справочники.Номенклатура.НайтиПоНаименованию("Торговая деятельность");
// Устанавливаем параметр запроса
Запрос.УстановитьПараметр("РодительскаяГруппа", ГруппаСсылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Здесь выполняем действия с найденной группой
Сообщить("Найдена группа: " + Выборка.Ссылка);
КонецЦикла;
Важный нюанс: Обратите внимание на свойство ЭтоГруппа. Оно позволяет отсеять конечные элементы (товары) и оставить только папки. Если вам нужны и папки, и товары, это условие можно просто убрать.
Иногда использование запроса кажется избыточным, особенно в простых обработках. В 1С у менеджеров справочников существует встроенный метод Выбрать(). Разберем по шагам, как он работает с иерархией.
Синтаксис метода следующий: Выбрать(<Родитель>, <Владелец>, <Отбор>, <Порядок>). Если мы передаем в первый параметр ссылку на конкретную группу, система вернет выборку элементов, находящихся непосредственно в ней.
Родитель = Справочники.Номенклатура.НайтиПоНаименованию("Торговая деятельность");
Выборка = Справочники.Номенклатура.Выбрать(Родитель);
Пока Выборка.Следующий() Цикл
Если Выборка.ЭтоГруппа Тогда
Сообщить("Найдена вложенная папка: " + Выборка.Наименование);
КонецЕсли;
КонецЦикла;
Проанализируем ограничение этого метода: он не работает рекурсивно. То есть, если внутри папки «Торговая деятельность» есть папка «Часы», а внутри «Часов» есть еще папки, метод Выбрать() вернет только папку «Часы». Чтобы получить всю глубину вложенности без запроса, пришлось бы писать рекурсивную функцию, что крайне не рекомендуется из-за низкой производительности.
В примерах выше мы использовали метод НайтиПоНаименованию(). Рассмотрим, почему это может быть опасно в реальных задачах:
Для повышения надежности рекомендуется использовать предопределенные элементы (если папка создана в Конфигураторе) или поиск по уникальному коду через НайтиПоКоду(), так как коды обычно защищены от случайного изменения.
Проанализируем ситуацию, когда нам нужно программно создать новый элемент в определенной папке, скопировав данные из другого объекта. Часто программисты сталкиваются с тем, что элемент упорно записывается в корень справочника, несмотря на установку родителя.
Рассмотрим ошибочный порядок действий:
НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
НовыйТовар.Родитель = НужнаяГруппа; // Установили родителя
ЗаполнитьЗначенияСвойств(НовыйТовар, ОбъектИсточник); // ОШИБКА: Родитель затерся!
НовыйТовар.Записать();
Выясним причину проблемы: Метод ЗаполнитьЗначенияСвойств копирует все совпадающие по имени поля. Если в ОбъектИсточник поле Родитель пустое (корень), то оно перезапишет ваше значение.
Правильное решение: Всегда устанавливайте специфические реквизиты (Родитель, Владелец) после массового заполнения свойств.
НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
// Сначала заполняем общие реквизиты (наименование, артикул и т.д.)
ЗаполнитьЗначенияСвойств(НовыйТовар, ОбъектИсточник);
// Затем принудительно устанавливаем правильное место в иерархии
НовыйТовар.Родитель = Справочники.Номенклатура.НайтиПоКоду("00001");
НовыйТовар.Записать();
Если перед вами стоит задача не выбрать список, а проверить, входит ли уже имеющийся элемент в конкретную группу (на любом уровне вложенности), воспользуйтесь встроенным методом ссылки ПринадлежитЭлементу(). Это гораздо быстрее, чем строить запрос для проверки одной ссылки.
Пример использования:
Если ОбъектНоменклатура.Ссылка.ПринадлежитЭлементу(ГруппаТорговля) Тогда
Сообщить("Этот товар относится к торговой деятельности");
КонецЕсли;
Подводя итог, для массового выбора иерархических данных всегда отдавайте предпочтение запросам с оператором В ИЕРАРХИИ. Это обеспечит стабильную работу системы даже при больших объемах данных и сложной структуре папок.