Суть проблемы
В программировании на платформе 1С, далее кратко "в 1С", чтобы удалить объект (или что тоже самое, запись) справочника, сначала надо получить объект, и только затем вызвать метод Удалить():
Код для копирования:
СпрОбъект = СправочникСсылка.ПолучитьОбъект();
СпрОбъект.Удалить();
По сути происходит самоудаление объекта из базы. По другому - никак.
Представим, что у вас имеется список элементов иерархического справочника, среди которых есть группы и элементы.
Требуется программно удалить каждый элемент списка, в том числе группы.
Если программно удалить группу, то вместе с ней удалятся все вложенные элементы справочника, в том числе вложенные группы.
Есть два способа перебрать элементы из справочника.
- Первый, пообъектно. Память компьютера занимается меньше по сравнению со вторым способом, но каждый раз обращается к базе данных для чтения и получения ссылки справочника со всеми реквизитами.
Синтаксис метода Выбрать:
Выбрать(<Родитель>, <Владелец>, <Отбор>, <Порядок>)
Код для копирования:
Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
СпрОбъект = Выборка.ПолучитьОбъект();
СпрОбъект.Удалить();
КонецЦикла;
- Второй, используя запросы. Память компьютера занимает больше по сравнению с первым способом - и может привести к ошибке "Нехватка памяти" при неправильно разработанном запросе, но обращается к базе данных для чтения и получения ссылок справочника один раз.
Код для копирования
ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Родитель КАК Родитель
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)";
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
//ГруппаПродукты заранее задана и известна
Запрос.УстановитьПараметр("Группа", ГруппаПродукты);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
СпрОбъект = Выборка.Ссылка.ПолучитьОБъект();
СпрОбъект.Удалить();
КонецЦикла;
Оба способа перебора элементов справочника (да и не только справочников, но и документов также) применяются в работе. Области применимости зависят от контекста, и постоянно требуется взвешенно подходить к выбору способа.
Например, при втором способе при удалении группы удаляются вложенные элементы и группы. А так как выборка получена заранее и обходится последовательно, то при очередной итерации получения ссылки из выборки возникнет ошибка, когда надо будет получить одну из удаленных вложенных ссылок на элемент или группу. В этом суть проблемы.
В общем случае, при удалении узла дерева, удаляются вложенные узлы дерева. Скажем так, работа с деревьями редко встречающаяся задача для программиста 1С.
И так как чаще работа с деревом в 1С происходит пообъектно, а не через запросную модель, и, наоборот, так как чаще работа со справочниками происходит через запросную модель, а не пообъектно, то выходит так, что с подобными проблемами при удалении элементов иерархического справочника программист 1С сталкивается внезапно и с непониманием, что происходит и как это обойти.
Способы обхода проблемы
Первый - использовать пообъектную модель перебора справочника.
Второй - использовать конструкцию Попытка Исключение КонецПопытки.
Третий способ - использовать любой алгоритм, учитывающий особенность удаления элементов иерархического справочника (в общем случае, дерева значений).
Вашему вниманию представлен один из алгоритмов.
Код для копирования
ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Родитель КАК Родитель
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)";
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
//ГруппаПродукты заранее задана и известна
Запрос.УстановитьПараметр("Группа", ГруппаПродукты);
Результат = Запрос.Выполнить();
ТЗ = Результат.Выгрузить();
Пока ТЗ.Количество()>0 Цикл
СтрТЗ = ТЗ.Получить(0);
//проверим зацикленность ссылки на родителе
МассивНайденныхСтрок = ТЗ.НайтиСтроки(Новый Структура("Родитель", СтрТЗ.Ссылка));
Если МассивНайденныхСтрок.Количество()>0 Тогда
ТЗ.Сдвинуть(0,ТЗ.Индекс(МассивНайденныхСтрок[МассивНайденныхСтрок.Количество()-1]));
Продолжить;
КонецЕсли;
Спр = СтрТЗ.Ссылка.ПолучитьОбъект();
ТЗ.Удалить(0); //удаляем из таблицы значений
Спр.Удалить(); //удаляем объект (элемент или группу) из справочника
КонецЦикла;
Пример, где я использую данный алгоритм, можно скачать по ссылке https://infostart.ru/1c/tools/1228926/
Всем добра! С пользой для всех, RustIG