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