Как преобразовать табличную часть программно полученного документа в ДанныеФормыКоллекция?

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

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

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

Понимаем природу ДанныеФормыКоллекция

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

  1. ТабличнаяЧасть — это объект базы данных (часть ДокументОбъект). С ним мы работаем на сервере, когда объект создан или получен из базы.
  2. ДанныеФормыКоллекция — это специализированный тип данных, существующий исключительно в контексте управляемой формы. Это "проекция" данных на клиент-серверную модель взаимодействия формы.

Многие разработчики пытаются создать ДанныеФормыКоллекция "в воздухе", чтобы передать их в какую-то процедуру. Давайте посмотрим, почему это не работает напрямую.

Почему не работает ЗначениеВДанныеФормы?

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


// ОШИБОЧНЫЙ ПОДХОД
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Попытка присвоить результат функции переменной
МояКоллекция = ЗначениеВДанныеФормы(ДокОбъект.Товары, ???); 

Здесь мы сталкиваемся с двумя проблемами:

Во-первых, метод ЗначениеВДанныеФормы() — это процедура, а не функция. Она ничего не возвращает. Если вы попытаетесь присвоить её результат переменной, вы получите Неопределено.

Во-вторых, у этой процедуры есть два обязательных параметра: Источник и Приемник. ЗначениеВДанныеФормы(Значение, ОбъектДанныхФормы).

Важно: Приемником должен быть уже существующий реквизит управляемой формы (или часть реквизита типа ДанныеФормыСтруктура). Вы не можете сконвертировать данные "в никуда". Платформе нужен конкретный контейнер на форме, куда она положит данные.

Правильное решение 1: Использование Таблицы Значений

Если ваша цель — просто обработать данные табличной части (перебрать строки, посчитать итоги, передать в другую процедуру) и при этом документ визуально не открыт, вам вообще не нужен тип ДанныеФормыКоллекция.

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


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

// Выгружаем табличную часть в Таблицу Значений
ТЗ_Товары = ДокОбъект.Товары.Выгрузить();

// Теперь мы можем работать с ТЗ стандартными методами
Для Каждого СтрокаТЗ Из ТЗ_Товары Цикл
    // Ваша логика обработки
    Сообщить("Товар: " + СтрокаТЗ.Номенклатура);
КонецЦикла;

Тип ТаблицаЗначений является "родным" для серверного кода 1С. Большинство процедур в типовых конфигурациях (включая БСП) умеют работать именно с таблицей значений. Если функция требует на вход коллекцию, чаще всего она примет и ТЗ.

Правильное решение 2: Если жестко требуется ДанныеФормыКоллекция

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

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


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

Обратите внимание: этот способ более ресурсоемкий. Мы изменяем структуру формы на лету. Используйте его только в крайних случаях.

Нюанс с выборкой и получением объекта

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

Объект ВыборкаИзРезультатаЗапроса не содержит табличных частей. Выборка — это способ последовательного чтения записей. Вы не можете обратиться к Выборка.Товары и ожидать там увидеть табличную часть.

Чтобы добраться до табличной части, необходимо получить сам объект документа. Рассмотрим правильную последовательность действий:


// 1. Выполняем запрос
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Документ.РеализацияТоваровУслуг ГДЕ ...");
Выборка = Запрос.Выполнить().Выбрать();

// 2. Итерируемся по выборке
Пока Выборка.Следующий() Цикл
    
    // 3. Получаем объект из ссылки
    // Важно: Табличные части доступны только у Объекта, а не у Ссылки или Выборки
    ТекОбъект = Выборка.Ссылка.ПолучитьОбъект();
    
    // 4. Работаем с табличной частью
    // Лучший вариант - выгрузить в ТЗ
    ТаблицаТоваров = ТекОбъект.Товары.Выгрузить();
    
    // Работаем с данными...
    
КонецЦикла;

Резюме

  1. Метод ЗначениеВДанныеФормы работает только если у вас есть заранее подготовленный реквизит на форме-приемнике. Он не создает данные "из воздуха".
  2. Для обработки данных без визуализации на форме используйте метод Выгрузить(), получая ТаблицаЗначений. Это наиболее производительный и простой способ.
  3. В выборке запроса нет табличных частей. Сначала нужно получить объект методом ПолучитьОбъект().
  4. Избегайте ненужных преобразований типов, если задача решается стандартными средствами языка (массивами структур или таблицами значений).
← На главную