Как правильно удалить строки связанной табличной части по условию в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке учетных механизмов в 1С часто возникает задача поддержания целостности данных между несколькими табличными частями объекта. Например, при удалении позиции из ведущей таблицы требуется автоматически очистить связанные с ней строки в подчиненной табличной части. Разберем по шагам, как корректно реализовать каскадное удаление строк, какие методы платформы для этого предназначены и каких типичных ошибок следует избегать.

Особенность метода Удалить() для табличных частей

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

Обратимся к синтаксис-помощнику платформы 1С: метод Удалить() у объекта ТабличнаяЧасть (а также у ТаблицаЗначений) перегружен и принимает один из двух типов параметров:

  1. Число — индекс удаляемой строки в коллекции (нумерация начинается с нуля).
  2. СтрокаТабличнойЧасти (или СтрокаТаблицыЗначений) — ссылка на сам объект строки, подлежащий удалению.

Благодаря этому для удаления найденных строк нет необходимости вычислять их индексы — достаточно передать полученный элемент строки напрямую в метод Удалить().

Решение 1: Поиск строк через НайтиСтроки() и последующее удаление

Рассмотрим стандартный и наиболее читаемый способ решения задачи, когда строк для удаления относительно немного. Сначала мы выполняем отбор строк с помощью структуры фильтра, а затем обходим полученный массив в цикле.

Посмотрим на пример кода:


ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Магазин", Элемент.ТекущаяСтрока.Магазин);

НайденныеСтроки = ПП_ТоварыМагазинов.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрДляУдаления Из НайденныеСтроки Цикл
    ПП_ТоварыМагазинов.Удалить(СтрДляУдаления);
КонецЦикла;

Разберем логику работы этого фрагмента:

  1. Метод НайтиСтроки() возвращает массив (Массив), содержащий ссылки на объекты СтрокаТабличнойЧасти, удовлетворяющие условию отбора.
  2. Цикл Для Каждого последовательно перебирает элементы массива.
  3. Метод Удалить() принимает саму строку и безопасно удаляет ее из подчиненной таблицы ПП_ТоварыМагазинов, не нарушая обход внешнего массива.

Решение 2: Обратный перебор по индексу через цикл Пока

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

Так как в языке 1С оператор Для ... По увеличивает счетчик только на +1, обратный перебор реализуется через цикл Пока:


Индекс = ПП_ТоварыМагазинов.Количество() - 1;
Пока Индекс >= 0 Цикл
    Если ПП_ТоварыМагазинов[Индекс].Магазин = ЗначениеОтбора Тогда
        ПП_ТоварыМагазинов.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
КонецЦикла;

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

Решение 3: Пакетная обработка через Таблицу Значений (для больших объемов)

Когда табличная часть содержит тысячи строк, многократный вызов метода Удалить() может работать медленно из-за постоянной перестройки внутренней структуры данных. В такой ситуации эффективнее применить подход с промежуточной таблицей значений:


ТЗ = ПП_ТоварыМагазинов.Выгрузить();

// Удаляем ненужные строки или копируем только нужные
ПараметрыОтбора = Новый Структура("Магазин", ЗначениеУдаляемогоМагазина);
МассивУдаляемых = ТЗ.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрТЗ Из МассивУдаляемых Цикл
    ТЗ.Строки.Удалить(СтрТЗ);
КонецЦикла;

// Загружаем очищенные данные обратно
ПП_ТоварыМагазинов.Загрузить(ТЗ);

Где размещать обработчик удаления в обычном приложении

Проанализируем события формы, в которых следует вызывать код удаления:

  1. ПередУдалением(Элемент, Отказ) — оптимальное событие табличного поля ведущей таблицы. Позволяет проверить наличие связанных данных, задать вопрос пользователю при необходимости или отменить действие, установив Отказ = Истина.
  2. Множественное выделение: Если у табличного поля включено свойство множественного выбора, обращение к Элемент.ТекущаяСтрока вернет только одну активную строку. В таком случае необходимо обрабатывать коллекцию Элемент.ВыделенныеСтроки.
  3. Модуль объекта: Для обеспечения надежности данных каскадную проверку или очистку «осиротевших» строк рекомендуется дублировать в событии ПередЗаписью модуля объекта, чтобы логика работала не только при интерактивных действиях в форме, но и при программной записи или обмене данными.
← На главную