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

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Способ 1. Удаление текущей строки по объектной ссылке

Рассмотрим самый быстрый способ исправления логики в существующем коде. Метод Добавить() коллекции строк табличной части возвращает ссылку на созданную строку типа СтрокаТабличнойЧасти. Эту переменную можно сразу передать в метод Удалить() табличной части при срабатывании условия превышения.

Посмотрим на пример реализации с прерыванием цикла:


Для Каждого Стр Из ТаблицаДокументов Цикл
    НовСтр = РасходныеНакладные.Добавить();
    НовСтр.РеализацияТоваровУслуг = Стр.Ссылка;
    НовСтр.Контрагент = Стр.Контрагент;
    НовСтр.Сумма = Стр.СуммаДокумента;
    
    ЗаполнитьОбщийВесРейса();
    ЗаполнитьОбщийОбъемРейса();
    
    Если Не Срочный Тогда
        Если ОбщийВесРН > Грузоподъемность Тогда
            Сообщить("Вес превышает установленные нормы");
            РасходныеНакладные.Удалить(НовСтр);
            Прервать;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

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

Способ 2. Удаление строки по индексу

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

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


Если ОбщийВесРН > Грузоподъемность Тогда
    Сообщить("Вес превышает установленные нормы");
    // Получаем последнюю строку коллекции и передаем ее в метод Удалить
    РасходныеНакладные.Удалить(РасходныеНакладные[РасходныеНакладные.Количество() - 1]);
    Прервать;
КонецЕсли;

Важный момент: при вызове метода Количество() обязательно указывайте круглые скобки. Данный способ работает корректно, однако обращение по переменной НовСтр из первого способа считается более читаемым и безопасным.

Способ 3. Предварительная проверка лимита перед добавлением строки (рекомендуемый)

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

Разберем алгоритм с накопительным итогом по шагам:

  1. Определяем текущий накопленный вес рейса перед началом цикла.
  2. Получаем вес и объем очередной накладной сразу из выборки запроса.
  3. Сравниваем планируемый суммарный вес с допустимой грузоподъемностью.
  4. Если лимит не превышен — добавляем строку и увеличиваем накопитель; если превышен — прерываем цикл без лишних манипуляций с табличной частью.

Посмотрим на пример реализации данного алгоритма:


ТекущийВесРейса = 0;

Для Каждого Стр Из ТаблицаДокументов Цикл
    // Проверяем, не превысит ли добавление текущего документа допустимую норму
    Если Не Срочный И (ТекущийВесРейса + Стр.ВесДокумента > Грузоподъемность) Тогда
        Сообщить("Вес превышает установленные нормы. Добавление накладных остановлено.");
        Прервать;
    КонецЕсли;
    
    НовСтр = РасходныеНакладные.Добавить();
    НовСтр.РеализацияТоваровУслуг = Стр.Ссылка;
    НовСтр.Контрагент = Стр.Контрагент;
    НовСтр.Сумма = Стр.СуммаДокумента;
    
    ТекущийВесРейса = ТекущийВесРейса + Стр.ВесДокумента;
КонецЦикла;

// Пересчитываем общие итоги один раз после заполнения
ЗаполнитьОбщийВесРейса();
ЗаполнитьОбщийОбъемРейса();

Рекомендации по оптимизации производительности

Проанализируем типичные узкие места, которые часто встречаются при программном заполнении табличных частей:

  1. Разыменование ссылок через точку: Конструкции вида Стр.Ссылка.Контрагент приводят к неявным SQL-запросам на каждой итерации цикла. Поле Контрагент необходимо получать напрямую в исходном запросе через ВЫБРАТЬ Реализация.Контрагент КАК Контрагент.
  2. Частый вызов процедур пересчета: Вызов процедур пересчета веса и объема внутри тела цикла приводит к тому, что табличная часть на каждой итерации обходится заново. Вызывайте функции пересчета итогов только один раз — после полного завершения цикла.
  3. Использование выборки вместо таблицы значений: Если результат запроса используется только для последовательного перебора, эффективнее применять конструкцию Выборка = Запрос.Выполнить().Выбрать() и обходить ее циклом Пока Выборка.Следующий() Цикл, что снижает нагрузку на оперативную память.
← На главную