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