Найти тему
1с разное

Удаление записей иерархического справочника в 1С, или использование метода ТаблицаЗначений.Сдвинуть()

Оглавление

Суть проблемы

В программировании на платформе 1С, далее кратко "в 1С", чтобы удалить объект (или что тоже самое, запись) справочника, сначала надо получить объект, и только затем вызвать метод Удалить():

Код для копирования:

СпрОбъект = СправочникСсылка.ПолучитьОбъект();
СпрОбъект.Удалить();

По сути происходит самоудаление объекта из базы. По другому - никак.

Представим, что у вас имеется список элементов иерархического справочника, среди которых есть группы и элементы.

-2

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

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

Есть два способа перебрать элементы из справочника.

  • Первый, пообъектно. Память компьютера занимается меньше по сравнению со вторым способом, но каждый раз обращается к базе данных для чтения и получения ссылки справочника со всеми реквизитами.
-3

Синтаксис метода Выбрать:
Выбрать(<Родитель>, <Владелец>, <Отбор>, <Порядок>)

Код для копирования:

Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл

СпрОбъект = Выборка.ПолучитьОбъект();
СпрОбъект.Удалить();

КонецЦикла;

  • Второй, используя запросы. Память компьютера занимает больше по сравнению с первым способом - и может привести к ошибке "Нехватка памяти" при неправильно разработанном запросе, но обращается к базе данных для чтения и получения ссылок справочника один раз.

-4

Код для копирования

ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Родитель КАК Родитель
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)";

Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;

//ГруппаПродукты заранее задана и известна
Запрос.УстановитьПараметр("Группа", ГруппаПродукты);

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

Пока Выборка.Следующий() Цикл

СпрОбъект = Выборка.Ссылка.ПолучитьОБъект();
СпрОбъект.Удалить();

КонецЦикла;

Оба способа перебора элементов справочника (да и не только справочников, но и документов также) применяются в работе. Области применимости зависят от контекста, и постоянно требуется взвешенно подходить к выбору способа.

Например, при втором способе при удалении группы удаляются вложенные элементы и группы. А так как выборка получена заранее и обходится последовательно, то при очередной итерации получения ссылки из выборки возникнет ошибка, когда надо будет получить одну из удаленных вложенных ссылок на элемент или группу. В этом суть проблемы.

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

И так как чаще работа с деревом в 1С происходит пообъектно, а не через запросную модель, и, наоборот, так как чаще работа со справочниками происходит через запросную модель, а не пообъектно, то выходит так, что с подобными проблемами при удалении элементов иерархического справочника программист 1С сталкивается внезапно и с непониманием, что происходит и как это обойти.

Способы обхода проблемы

Первый - использовать пообъектную модель перебора справочника.

Второй - использовать конструкцию Попытка Исключение КонецПопытки.

-5

Третий способ - использовать любой алгоритм, учитывающий особенность удаления элементов иерархического справочника (в общем случае, дерева значений).

Вашему вниманию представлен один из алгоритмов.

-6

Код для копирования

ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Родитель КАК Родитель
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)";

Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
//ГруппаПродукты заранее задана и известна
Запрос.УстановитьПараметр("Группа", ГруппаПродукты);

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

Пока ТЗ.Количество()>0 Цикл

СтрТЗ = ТЗ.Получить(0);

//проверим зацикленность ссылки на родителе
МассивНайденныхСтрок = ТЗ.НайтиСтроки(Новый Структура("Родитель", СтрТЗ.Ссылка));
Если МассивНайденныхСтрок.Количество()>0 Тогда
ТЗ.Сдвинуть(0,ТЗ.Индекс(МассивНайденныхСтрок[МассивНайденныхСтрок.Количество()-1]));
Продолжить;
КонецЕсли;

Спр = СтрТЗ.Ссылка.ПолучитьОбъект();
ТЗ.Удалить(0); //удаляем из таблицы значений
Спр.Удалить(); //удаляем объект (элемент или группу) из справочника
КонецЦикла;

Пример, где я использую данный алгоритм, можно скачать по ссылке https://infostart.ru/1c/tools/1228926/

Всем добра! С пользой для всех, RustIG