Как правильно удалить строку из табличной части в 1С:Предприятие 8

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

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

Базовый метод удаления одиночной строки

Для удаления строки на уровне программного объекта (например, ДокументОбъект) используется метод Удалить() коллекции табличной части. Важно понимать, что этот метод может принимать как целочисленный индекс строки, так и саму строку как объект. Рассмотрим простейший пример удаления по индексу.

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


// Получаем объект документа по ссылке
ДокументОбъект = СсылкаНаКонкретныйДокумент.ПолучитьОбъект();

// Предположим, нам нужно удалить строку, индекс которой известен
// Помним, что индексация начинается с нуля
ИндексСтроки = 0; // Это первая строка в табличной части
ДокументОбъект.Товары.Удалить(ИндексСтроки);

// Обязательно записываем объект, чтобы изменения отразились в базе данных
ДокументОбъект.Записать();

Здесь крайне важно обратить внимание на разницу между индексом и номером строки. В системе 1С свойство НомерСтроки — это порядковое число, которое начинается с 1. Оно служит для визуального отображения и упорядочивания. Индекс же — это программный идентификатор позиции элемента в коллекции, и он всегда начинается с 0. Поэтому при удалении строки по визуальному номеру всегда нужно вычитать единицу: Удалить(НомерСтроки - 1).

Почему НомерСтроки не всегда совпадает с Индексом + 1

Проанализируем ситуацию, в которой использование НомерСтроки для определения индекса может привести к ошибке — решить проблему поможет анализ истории версий и пакетная отмена изменений. Номер строки пересчитывается системой не мгновенно. Если пользователь или программа удалили несколько строк в процессе редактирования, или если табличная часть была программно отсортирована, визуальный НомерСтроки может перестать соответствовать физическому порядку элементов в коллекции ТабличнаяЧасть.

Рассмотрим пример: если вы удалите вторую строку из пяти, то бывшая третья строка визуально станет второй (после записи или обновления), но ее положение в памяти до момента фиксации изменений может быть специфическим. Поэтому самым надежным способом удаления конкретной строки, которую вы уже «держите» в переменной (например, получили через поиск), является передача в метод Удалить() самой строки, а не ее индекса.


// Поиск строки по значению реквизита
ПараметрыПоиска = Новый Структура("Номенклатура", НужныйТовар);
НайденныеСтроки = ДокументОбъект.Товары.НайтиСтроки(ПараметрыПоиска);

Если НайденныеСтроки.Количество() > 0 Тогда
    // Удаляем конкретный объект строки, найденный в коллекции
    ДокументОбъект.Товары.Удалить(НайденныеСтроки[0]);
КонецЕсли;

Массовое удаление строк: проблема прямого цикла

Типичная ошибка при необходимости удалить несколько строк по условию (поможет универсальный инструмент поиска и удаления данных) — использование прямого цикла Для Счетчик = 0 По ТЧ.Количество() - 1 Цикл. Выясним причину, по которой этот метод не работает. Когда вы удаляете строку с индексом 0, строка, которая была под индексом 1, мгновенно перемещается на позицию 0. Счетчик цикла при этом увеличивается до 1. В итоге программа «перепрыгивает» через строку, и часть данных остается необработанной.

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


КоличествоСтрок = Объект.Товары.Количество();

// Двигаемся с конца к началу
Для Индекс = 1 По КоличествоСтрок Цикл
    ТекущийИндекс = КоличествоСтрок - Индекс;
    СтрокаТЧ = Объект.Товары[ТекущийИндекс];
    
    // Проверяем условие удаления
    Если СтрокаТЧ.Количество == 0 Тогда
        Объект.Товары.Удалить(ТекущийИндекс);
    КонецЕсли;
КонецЦикла;

Альтернативный и более современный способ — использование вспомогательного массива. Мы сначала находим все строки, подлежащие удалению, сохраняем ссылки на них в массив, а затем обходим массив и удаляем строки из табличной части.


// Шаг 1: Находим строки
СтруктураПоиска = Новый Структура("Статус", "Удалить");
МассивСтрокДляУдаления = Объект.Товары.НайтиСтроки(СтруктураПоиска);

// Шаг 2: Удаляем их из коллекции
Для Каждого СтрокаИзСписка Из МассивСтрокДляУдаления Цикл
    Объект.Товары.Удалить(СтрокаИзСписка);
КонецЦикла;

Удаление строк на уровне управляемой формы

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


// Получаем идентификатор текущей строки на форме
ИдентификаторСтроки = Элементы.Товары.ТекущаяСтрока;

Если ИдентификаторСтроки <> Неопределено Тогда
    // Удаляем строку из данных формы
    Объект.Товары.Удалить(ИдентификаторСтроки);
КонецЕсли;

Обратите внимание: на форме метод Удалить() у объекта ДанныеФормыКоллекция (которым является Объект.Товары) принимает идентификатор строки, а не индекс. Это позволяет системе однозначно определить строку, даже если в таблице включены фильтры или сортировки.

Оптимизация: когда строк слишком много

Если табличная часть содержит десятки тысяч строк и вам нужно удалить значительную их часть (например, более 50%), стандартный метод Удалить() в цикле может работать медленно, так как после каждого удаления система пересчитывает индексы коллекции — для этого подойдёт обработка массовой очистки базы и табличных частей. В таких случаях проанализируем метод полной перезагрузки.

  1. Выгружаем табличную часть в Таблицу Значений.
  2. Удаляем ненужные строки в таблице значений (это происходит быстрее) или создаем новую таблицу только с нужными данными.
  3. Очищаем исходную табличную часть методом Очистить().
  4. Загружаем данные обратно методом Загрузить().

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

Заключение и рекомендации

Подводя итог, выделим основные правила безопасного удаления строк в 1С:

Соблюдение этих простых правил позволит избежать трудноуловимых ошибок «пропуска строк» и обеспечит высокую производительность вашего кода при работе с табличными данными — поможет инструмент написания и проверки синтаксиса кода 1С.

← На главную