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

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

Заполнение табличной части одного объекта данными из другого — одна из самых частых задач, с которыми сталкивается начинающий разработчик в среде 1С:Предприятие 8. Несмотря на кажущуюся простоту, здесь есть свои тонкости: от правильного синтаксиса циклов до выбора наиболее производительного метода копирования данных. В этой статье мы подробно разберем, почему возникают ошибки при обходе коллекций, и рассмотрим несколько эффективных способов решения этой задачи.

Разбор ошибки в синтаксисе цикла Для каждого

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


Для Каждого Объект.ДокументОтгрузкиОснование.Товары.Строка Из Объект.ДокументОтгрузкиОснование.Товары Цикл 
    НовСтр = Объект.Товары.Добавить();
    НовСтр.Номенклатура = Объект.ДокументОтгрузкиОснование.Товары.Номенклатура;
КонецЦикла;

Проанализируем причину ошибки. В конструкции Для Каждого ... Из ... Цикл первым параметром должно выступать имя новой переменной (итератора), в которую на каждом шаге цикла платформа будет помещать текущую строку коллекции. Использование сложного пути через точку, такого как Объект.ДокументОтгрузкиОснование.Товары.Строка, недопустимо. Платформа ожидает простое имя переменной.

Правильный вариант использования цикла выглядит так:


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

В данном примере ТекСтрока — это итератор, который при каждом повторении цикла становится ссылкой на очередную строку табличной части Товары документа-основания.

Оптимальный способ: Методы Загрузить и Выгрузить

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

Посмотрим на пример кода, который делает ту же работу в одну строку:


Объект.Товары.Загрузить(Объект.ДокументОтгрузкиОснование.Товары.Выгрузить());

Разберем по шагам, что здесь происходит:

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

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

Универсальное копирование свойств через ЗаполнитьЗначенияСвойств

Когда нам нужно перенести множество реквизитов (Номенклатура, Количество, Цена, СтавкаНДС и т.д.), прописывать каждую строку вручную утомительно и чревато ошибками. Проанализируем ситуацию: как упростить код, если в строках много одноименных колонок?

Для этого идеально подходит функция ЗаполнитьЗначенияСвойств. Перепишем наш цикл с ее использованием:


Для Каждого СтрИсточник Из Объект.ДокументОтгрузкиОснование.Товары Цикл
    НовСтр = Объект.Товары.Добавить();
    ЗаполнитьЗначенияСвойств(НовСтр, СтрИсточник);
КонецЦикла;

Эта функция автоматически найдет все совпадающие по именам свойства у объекта СтрИсточник (строка-источник) и НовСтр (новая строка-приемник) и скопирует их значения. Это делает код более устойчивым к изменениям в конфигурации: если вы добавите новый реквизит в обе табличные части, код не придется переписывать.

Производительность и работа на больших объемах данных

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

Рассмотрим более профессиональный подход:

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

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

Контекст исполнения: Клиент или Сервер?

При программном заполнении крайне важно учитывать, где исполняется код. Рассмотрим типичную ошибку начинающих: обращение к данным другого документа через точку на клиенте. Код типа Объект.ДокументОтгрузкиОснование.Товары в клиентской процедуре заставит систему выполнить неявный вызов сервера для получения данных. Если строк много, это приведет к "зависанию" интерфейса.

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

Копирование с условием (фильтрация данных)

Часто требуется перенести не все позиции, а только определенные. Посмотрим на пример использования метода НайтиСтроки() или Скопировать() у таблицы значений:


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

Заключение

Мы проанализировали основные способы заполнения табличных частей. Для простых задач, где нужно скопировать всё "как есть", лучше всего подходит связка Загрузить(Выгрузить()). Для выборочного переноса или переноса с изменением данных используйте цикл Для каждого с обязательным созданием переменной-итератора и функцией ЗаполнитьЗначенияСвойств для сокращения кода. Всегда помните о контексте исполнения и старайтесь переносить тяжелые операции по обработке данных на сервер.

← На главную