Разработка и Конфигурация · 11 мин
Как программно очистить табличную часть документа в 1С
Как программно очистить табличную часть документа в 1С: метод Очистить(), удаление строк в цикле, работа с формой, типовые ошибки и примеры кода для 8.2 и 8.3.
Табличная часть документа в 1С — это коллекция строк, и очистить её программно можно несколькими способами: методом Очистить(), удалением строк в цикле или установкой отбора с последующим удалением. Выбор способа зависит от того, где выполняется код — в модуле объекта, в модуле формы или во внешней обработке — и нужно ли удалить все строки или только часть.
Чаще всего задача сводится к одной строке кода: Объект.Товары.Очистить();. Однако на практике возникают нюансы: очистка из формы требует обращения через объект данных формы, при управляемых формах важно учитывать контекст сервера и клиента, а удаление строк в цикле «вперёд» приводит к пропуску элементов. Разберём все рабочие варианты с примерами.
Материал ориентирован на платформу 1С:Предприятие 8.2 и 8.3, но синтаксис работы с табличными частями един и для более ранних версий линейки 8.x. Примеры приведены на встроенном языке и подходят как для управляемых, так и для обычных форм с учётом указанных оговорок.
Метод Очистить() — самый простой способ
У коллекции строк табличной части есть встроенный метод Очистить(), который удаляет все строки за один вызов. Это оптимальный вариант, когда нужно полностью освободить табличную часть перед новым заполнением.
// В модуле объекта или внешней обработке
ДокОбъект = Документы.РеализацияТоваровУслуг.НайтиПоНомеру(НомерДок, ДатаДок).ПолучитьОбъект();
ДокОбъект.Товары.Очистить();
ДокОбъект.Записать();
Если код выполняется в модуле самого документа (например, в обработчике ПередЗаписью или ОбработкаЗаполнения), обращение ещё короче:
Товары.Очистить();
Метод не возвращает значения и не вызывает запись документа сам по себе. Если вы получили объект через ПолучитьОбъект() во внешней обработке и не вызвали Записать(), изменения останутся только в памяти и будут потеряны.
Очистка табличной части из формы документа
В модуле формы обращение напрямую к Товары.Очистить() не сработает, потому что данные документа на форме представлены через реквизит формы (обычно Объект). Правильное обращение:
&НаКлиенте
Процедура ОчиститьТовары(Команда)
Объект.Товары.Очистить();
КонецПроцедуры
Для управляемой формы такой код безопасно выполнять на клиенте — табличная часть доступна в клиентском контексте. Если же очистка является частью сложной серверной логики, вызывайте серверную процедуру, но помните: изменения, сделанные на сервере, автоматически отразятся в форме после возврата управления.
После очистки из формы полезно установить признак модифицированности, чтобы пользователь не потерял изменения при закрытии: платформа обычно делает это сама при изменении данных, но при программных манипуляциях в обход стандартных механизмов проверьте свойство Модифицированность формы.
Выборочное удаление строк в цикле
Когда нужно удалить не все строки, а только удовлетворяющие условию, используют цикл. Главная ловушка — удаление при прямом обходе: после удаления строки индексы сдвигаются, и следующая строка пропускается.
Обход в обратном порядке
Для Индекс = 1 По Объект.Товары.Количество() Цикл
СтрокаТЧ = Объект.Товары[Объект.Товары.Количество() - Индекс];
Если СтрокаТЧ.Количество = 0 Тогда
Объект.Товары.Удалить(СтрокаТЧ);
КонецЕсли;
КонецЦикла;
Такой подход корректен, потому что удаление «хвостовых» строк не влияет на индексы ещё не обработанных элементов в начале коллекции.
Через массив найденных строк
Более читаемый вариант — сначала собрать строки для удаления, затем удалить их отдельным проходом:
СтрокиКУдалению = Новый Массив;
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
Если СтрокаТЧ.Количество = 0 Тогда
СтрокиКУдалению.Добавить(СтрокаТЧ);
КонецЕсли;
КонецЦикла;
Для Каждого СтрокаТЧ Из СтрокиКУдалению Цикл
Объект.Товары.Удалить(СтрокаТЧ);
КонецЦикла;
Этот способ удобен, когда условие сложное или когда строки нужно предварительно показать пользователю для подтверждения.
Очистка и связанные с ней механизмы
Табличная часть документа редко существует изолированно. Перед программной очисткой оцените, что затронет операция.
Движения по регистрам. Если документ проведён, его движения сформированы на основании строк табличных частей. Очистка строк без перепроведения оставит в регистрах старые записи. После очистки документ следует перепровести (Записать(РежимЗаписиДокумента.Проведение)) или отменить проведение.
Итоговые поля на форме. Суммы документа, отображаемые в шапке или подвале, часто рассчитываются по строкам табличной части. После программной очистки вызовите процедуру пересчёта итогов, если она предусмотрена конфигурацией, или обновите соответствующие реквизиты вручную.
Зависимые табличные части. В типовых конфигурациях очистка одной табличной части (например, «Товары») может требовать синхронной очистки другой (например, «Серии» или «Услуги»), иначе в документе останутся «осиротевшие» строки.
Пакетная очистка во внешней обработке
Типовой сценарий администрирования — очистить табличные части у группы документов, например удалить строки по определённой номенклатуре из всех документов за период. Каркас такой обработки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТовары.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Номенклатура = &Номенклатура
| И РеализацияТовары.Ссылка.Дата МЕЖДУ &Начало И &Конец";
// ... установка параметров и обход выборки
Пока Выборка.Следующий() Цикл
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
// выборочное удаление или полная очистка
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
Для больших объёмов полезно выполнять обработку в транзакции с фиксацией порциями, чтобы не блокировать таблицы надолго и не потерять весь результат при сбое на последнем документе.
- 1Сделайте резервную копию базы или работайте на копии
- 2Запросом отберите документы, подлежащие обработке
- 3Для каждого документа получите объект и очистите табличную часть методом Очистить() или удалите строки выборочно
- 4Запишите документ с нужным режимом: запись, проведение или отмена проведения
- 5Проверьте результат на нескольких документах вручную
Альтернативы: загрузка пустой таблицы и обмен данными
Иногда вместо построчного удаления удобнее загрузить в табличную часть пустую таблицу значений методом Загрузить():
ПустаяТЗ = Объект.Товары.Выгрузить();
ПустаяТЗ.Очистить();
Объект.Товары.Загрузить(ПустаяТЗ);
По результату это эквивалентно Очистить(), но приём полезен, когда табличную часть нужно заменить заранее подготовленным набором строк — тогда загрузка выполняется той же командой.
При обмене данными (конвертация, синхронизация) очистка табличной части перед загрузкой новых строк — стандартный приём в обработчиках «Перед записью». Здесь важно очищать только при реальной замене данных, иначе при частичных выгрузках можно стереть строки, которые не приходили в пакете обмена.
Сравнение способов очистки
Полное удаление всех строк одной командой. Самый быстрый и читаемый вариант, но не подходит для выборочного удаления
Выборочное удаление по условию. Требует аккуратности с индексами, чуть больше кода
Выборочное удаление сложным условием с возможностью предварительного просмотра. Расходует память на массив ссылок на строки
Замена содержимого целиком. Уместно, когда дальше загружается новый набор строк
Проверка результата
После очистки убедитесь, что операция выполнена полностью и не нарушила связанные данные.
Как проверить результат
ТабличнаяЧасть.Количество() = 0 после Очистить()
Строки остались — возможно, очищалась другая табличная часть или копия данных
После Записать() документ открывается с пустой табличной частью
В форме строки есть, в базе нет (или наоборот) — объект не записан
После перепроведения движения соответствуют пустой табличной части
Старые движения остались — документ не был перепроведён
Сумма документа пересчитана и равна нулю
Шапка показывает старую сумму — не вызван пересчёт итогов
Программно проверить результат можно сразу после записи, повторно прочитав объект из базы и сравнив количество строк. Это особенно полезно в пакетных обработках — добавьте в цикл контроль и журналирование, чтобы видеть, на каких документах операция завершилась с ошибкой.
Что важно запомнить
Полная очистка — Объект.Товары.Очистить() с последующим Записать(). Выборочное удаление — цикл в обратном порядке или массив найденных строк. Из формы обращайтесь через реквизит Объект. Проведённый документ после очистки перепроведите, а массовую обработку запускайте только после резервного копирования.
Частые вопросы
Можно ли очистить табличную часть без получения объекта документа?
Нет. Табличная часть хранится вместе с документом, и изменить её можно только через объект, полученный методом ПолучитьОбъект(), либо через форму документа. Прямые запросы к таблице табличной части в языке запросов доступны только на чтение.
Почему после Очистить() строки снова появляются при открытии документа?
Потому что метод меняет данные только в памяти. Если после очистки не был вызван Записать(), в базе осталась прежняя версия документа. Добавьте запись объекта и проверьте, не отменяет ли изменения обработчик ПередЗаписью.
Как очистить табличную часть у проведённого документа?
Получите объект, очистите табличную часть и запишите документ с режимом РежимЗаписиДокумента.Проведение, чтобы движения по регистрам пересчитались. Если проведение не требуется, сначала отмените проведение, очистите строки и запишите в режиме простой записи.
Почему в цикле Для Каждого удаляется не каждая строка?
При удалении элемента коллекция перестраивается: индексы сдвигаются, и итератор пропускает следующую строку. Используйте обход в обратном порядке по индексу или сначала соберите строки в массив, а затем удаляйте их отдельным циклом.
Как очистить табличную часть в управляемой форме на клиенте?
Обратитесь к данным через реквизит формы: Объект.Товары.Очистить(). Табличная часть доступна в клиентском контексте, поэтому серверный вызов для простой очистки не нужен. Серверная процедура потребуется, только если очистка связана с обращением к базе данных.
Есть ли разница между Очистить() и Удалить() в цикле по скорости?
Для полного удаления всех строк Очистить() предпочтительнее: это одна атомарная операция над коллекцией. Цикл с Удалить() оправдан только при выборочном удалении, когда проверяется условие для каждой строки.