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

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

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

Разбор типичной ошибки: Строка против Ссылки

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

Запрос.УстановитьПараметр("Документ", "&Ссылка.Документ");

Проанализируем, почему этот код не работает. В системе 1С:Предприятие существует четкое различие между типами данных. В данном случае в параметр "Документ" передается Строка, содержащая текст "&Ссылка.Документ". Однако в тексте запроса при сравнении поля Ссылка с параметром, СУБД ожидает объект типа Ссылка (например, ДокументСсылка.БанковскаяВыписка). Сравнение ссылки со строкой всегда будет давать результат "Ложь", поэтому запрос вернет пустой результат, и система выдаст сообщение: "Нечего добавлять!".

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

Способ 1: Использование запроса (Оптимальный для производительности)

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

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


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

    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    ВыпискаЗаказы.Товар КАК Товар,
    |    ВыпискаЗаказы.Количество КАК Количество,
    |    ВыпискаЗаказы.Цена КАК Цена,
    |    ВыпискаЗаказы.Сумма КАК Сумма
    |ИЗ
    |    Документ.БанковскаяВыписка.Заказы КАК ВыпискаЗаказы
    |ГДЕ
    |    ВыпискаЗаказы.Ссылка = &СсылкаНаДокумент";

    // Здесь мы передаем реальную ссылку из реквизита объекта
    Запрос.УстановитьПараметр("СсылкаНаДокумент", Объект.ДокументОснование);

    РезультатЗапроса = Запрос.Выполнить();

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

Способ 2: Обход коллекции строк (Без использования запроса)

Если документ-источник уже доступен (например, выбран в реквизите формы) и объем данных невелик, мы можем обойтись без запроса, обратившись к табличной части через точку. Этот метод проще в написании, но может работать медленнее на больших объемах данных, так как платформа считывает весь объект целиком из базы данных.

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


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

    Объект.Заказы.Очистить();

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

Оптимизация: Использование метода Загрузить()

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


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

Важные рекомендации при разработке

  1. Контекст исполнения: Всегда помните, что работа с базой данных (запросы, обращение к табличным частям документов через ссылки) должна происходить &НаСервере. На клиенте ссылка — это лишь идентификатор, который не содержит данных строк.
  2. Очистка перед заполнением: Перед тем как добавлять новые строки, решите, нужно ли очищать существующие данные методом Объект.ИмяТЧ.Очистить(). Обычно пользователи ожидают полной перезаписи при нажатии кнопки "Заполнить".
  3. Проверка на пустые значения: Всегда проверяйте результат метода Выполнить() с помощью Пустой(), чтобы не производить лишних действий в памяти сервера.
  4. Типизация параметров: Если вы используете консоль запросов для отладки, помните, что в коде 1С параметры передаются как объекты. Вместо "ДокументСсылка.БанковскаяВыписка" (строка) передавайте Объект.Ссылка или результат поиска по коду/номеру.

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

← На главную