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