согласно инструкции. Ниже представлен полный текст страницы. Как правильно очистить табличную часть документа в 1С 8.3 на клиенте и сервере?

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

Работа с табличными частями (ТЧ) — одна из самых частых задач, с которыми сталкивается разработчик в среде «1С:Предприятие 8». Несмотря на кажущуюся простоту операции очистки, на практике часто возникают ситуации, когда написанный код не выдает ошибок, но табличная часть физически остается заполненной. Или наоборот — система генерирует неочевидные ошибки времени выполнения.

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


Сценарий 1. Очистка табличной части у объекта в базе данных

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

Основная ошибка начинающих разработчиков заключается в попытке обратиться к табличной части непосредственно через ссылку. Проанализируем типичный ошибочный код:


// ОШИБОЧНЫЙ КОД
СсылкаНаДокумент = Справочники.Договоры.ПустаяСсылка(); // или Ссылка на Документ
СсылкаНаДокумент.Товары.Очистить(); // Вызовет ошибку выполнения!

Платформа 1С строго разделяет объекты базы данных на два типа: Ссылки (предназначены только для чтения и идентификации) и Объекты (предназначены для изменения данных). Метод Очистить() применим только к объекту.

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

  1. Получаем объект из имеющейся ссылки с помощью метода ПолучитьОбъект().
  2. Вызываем метод Очистить() для нужной табличной части.
  3. Критически важный шаг: вызываем метод Записать(). Если этого не сделать, изменения останутся только в оперативной памяти компьютера и не будут сохранены в базе данных СУБД.

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


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

Если ДокументОбъект <> Неопределено Тогда
    // Очищаем табличную часть "Товары"
    ДокументОбъект.Товары.Очистить();
    
    // Записываем документ для фиксации изменений в базе данных
    ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецЕсли;

Обратите внимание: при вызове метода Записать() мы передаем режим записи. Если документ не должен проводиться повторно (или вообще еще не был проведен), используем параметр РежимЗаписиДокумента.Запись.


Сценарий 2. Очистка табличной части на управляемой форме (на клиенте)

Теперь разберем ситуацию, когда пользователь работает непосредственно с формой документа (например, в интерактивном режиме или при нажатии кнопки на форме), и нам требуется моментально очистить данные на экране.

В управляемом приложении данные формы представлены специальным типом ДанныеФормыКоллекция (для табличных частей) и ДанныеФормыСтруктура (для самого объекта формы). В этом контексте нам не требуется обращаться к базе данных и записывать документ. Мы работаем напрямую с экранными данными пользователя.

Выясним причину, почему для простой очистки на форме не нужно делать серверных вызовов. Вызов сервера — это всегда ресурсоемкая операция (сериализация данных, передача по сети, десериализация). Если перед нами стоит задача просто очистить ТЧ «здесь и сейчас», мы делаем это прямо на клиенте.

Рассмотрим пример клиентской процедуры:


&НаКлиенте
Процедура ОчиститьТабличнуюЧастьНаКлиенте(Команда)
    
    // "Объект" - это стандартный реквизит управляемой формы типа ДанныеФормыСтруктура
    // "Товары" - табличная часть (ДанныеФормыКоллекция)
    Объект.Товары.Очистить(); 
    
    // Данные на форме обновятся мгновенно и автоматически!
    
КонецПроцедуры

Этот код отработает мгновенно, интерфейс не «моргнет», а пользователь сразу увидит пустую таблицу, которую он сможет заполнить заново или просто закрыть форму без сохранения изменений, если передумает.


Сценарий 3. Передача объекта формы на сервер и обратно (Контекстный вызов)

Часто в реальной практике очистка табличной части завязана на сложную серверную бизнес-логику. Например, перед очисткой нужно проверить остатки на складах, сделать сложный запрос к базе данных или перезаполнить ТЧ по какому-то алгоритму. В этом случае без сервера не обойтись.

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

При передаче переменной типа ДанныеФормыСтруктура (наш Объект) в процедуру с директивой &НаСервереБезКонтекста или при передаче через параметры в обычную серверную процедуру происходит копирование данных. Изменения, внесенные на сервере в этот локальный параметр, не возвращаются на клиент автоматически.

Существует два правильных способа решения этой задачи.

Способ А. Классический переход «Реквизит в Значение» и обратно

Это самый надежный способ, когда вам требуется выполнить очистку ТЧ и сопутствующую обработку именно методами самого прикладного объекта (документа), задействовав логику его модуля. Мы используем встроенные функции платформы для конвертации данных формы в объект базы данных.

Рассмотрим по шагам этот код:


&НаКлиенте
Процедура ВыполнитьОчисткуИОбработку(Команда)
    // Вызываем серверную контекстную процедуру
    ОчиститьТЧНаСервере();
КонецПроцедуры

&НаСервере
Процедура ОчиститьТЧНаСервере()
    
    // Шаг 1: Конвертируем данные формы в реальный прикладной объект "ДокументОбъект"
    ДокОбъект = РеквизитФормыВЗначение("Объект");
    
    // Шаг 2: Теперь у нас есть полноценный объект 1С. Очищаем его табличную часть
    ДокОбъект.Товары.Очистить();
    
    // Здесь также можно вызвать любые процедуры из модуля этого документа, например:
    // ДокОбъект.ЗаполнитьЦены();
    
    // Шаг 3: Возвращаем измененный объект обратно в реквизит управляемой формы
    ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
    
    // Теперь клиентская форма сразу отобразит изменения пользователю
    
КонецПроцедуры

Способ Б. Использование метода КопироватьДанныеФормы

Если вы разрабатываете внешнюю обработку или логику, которая работает с формой извне (как в сообщении 7 и 14 из темы форума), и передаете структуру формы как параметр на сервер, вам необходимо явно вернуть измененные данные.

Для этого используется глобальный метод КопироватьДанныеФормы(Источник, Приемник). Посмотрим на пример кода:


&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
    
    ПараметрыФормы = Новый Структура("Ключ", ОбъектыНазначенияМассив[0]);
    Форма = ПолучитьФорму("Документ.СчетНаОплатуПокупателю.Форма.ФормаДокумента", ПараметрыФормы);
    
    // Получаем структуру данных формы документа
    ОбъектФормы = Форма.Объект;
    
    // Создаем временную копию данных для передачи на сервер
    ОчиститьТЧНаСервереВнешнейПроцедурой(ОбъектФормы);
    
    // Копируем измененные на сервере данные обратно в контекст формы документа
    КопироватьДанныеФормы(ОбъектФормы, Форма.Объект);
    
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ОчиститьТЧНаСервереВнешнейПроцедурой(ДокументДанныеФормы)
    
    // На сервере очищаем ТЧ переданного параметра
    ДокументДанныеФормы.Товары.Очистить();
    
КонецПроцедуры

Продвинутые техники работы с табличными частями

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

Быстрая очистка (обнуление) одной конкретной колонки без циклов

Представим, что в табличной части «Товары» (содержащей сотни строк) вам нужно очистить только колонку «Количество», оставив саму номенклатуру нетронутой. Обычный перебор строк в цикле Для Каждого на сервере работает крайне медленно на больших объемах данных.

Для оптимизации этой операции мы можем применить продвинутый метод работы с коллекциями — ЗагрузитьКолонку(). Поскольку у ТЧ документов нет стандартного метода ЗаполнитьЗначения() (как у ТаблицыЗначений), мы используем трюк с инициализацией пустого массива:


&НаСервере
Процедура ОбнулитьКолонкуКоличество(ДокументОбъект)
    
    КоличествоСтрок = ДокументОбъект.Товары.Количество();
    
    // Создаем массив, размер которого в точности равен количеству строк в ТЧ.
    // При создании он будет автоматически заполнен значениями Неопределено (или 0, если задать явно)
    МассивПустыхЗначений = Новый Массив(КоличествоСтрок);
    
    // Быстро записываем пустые значения во всю колонку ТЧ одной операцией
    ДокументОбъект.Товары.ЗагрузитьКолонку(МассивПустыхЗначений, "Количество");
    
    // Этот метод работает в десятки раз быстрее классического перебора строк в цикле!
    
КонецПроцедуры

Частичная очистка: Удаление строк по условию (Классическая ловушка)

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

Рассмотрим, почему обычный цикл Для Каждого работает неверно при удалении элементов:


// ОШИБОЧНЫЙ КОД (так делать нельзя!)
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    Если СтрокаТЧ.Количество = 0 Тогда
        Объект.Товары.Удалить(СтрокаТЧ); // Индексы коллекции сдвигаются, следующая строка проскакивает мимо цикла!
    КонецЕсли;
КонецЦикла;

Чтобы избежать этой проблемы, используем один из двух правильных подходов.

Вариант 1. Обход коллекции с конца (по индексу). При удалении строк с конца сдвиг индексов никак не влияет на еще не обработанные элементы, находящиеся в начале таблицы.


Индекс = Объект.Товары.Количество() - 1;

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

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


СтрокиДляУдаления = Новый Массив;

// Шаг 1: Находим подходящие под условие строки
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    Если СтрокаТЧ.Количество = 0 Тогда
        СтрокиДляУдаления.Добавить(СтрокаТЧ);
    КонецЕсли;
КонецЦикла;

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

Влияние объема данных на производительность интерфейса

Если в вашем документе содержатся тысячи строк (например, это крупная накладная поступления товаров или отчет о розничных продажах), вызов метода Очистить() непосредственно на клиенте для связанных данных формы может вызвать временное «зависание» интерфейса 1С.

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

В случае работы с экстремально большими объемами данных рекомендуется:

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

← На главную