Как преобразовать табличную часть формы в таблицу значений в 1С:Предприятии 8.3?

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

При работе с формами в 1С:Предприятии 8.3 программисты часто сталкиваются с необходимостью получить данные из табличной части, отображаемой на форме, в виде ТаблицыЗначений для дальнейшей программной обработки. Однако прямой перевод может вызвать сложности, особенно если не знать специфику работы с управляемыми формами. Рассмотрим эту проблему подробнее и выясним, как ее эффективно решить.

Почему возникла ошибка "Несоответствие типов"?

Начнем с анализа первоначальной проблемы, описанной автором темы. Автор пытался преобразовать табличную часть Объект.Товары в ТаблицуЗначений различными способами, используя функции РеквизитФормыВЗначение и ДанныеФормыВЗначение, но каждый раз получал ошибку "Несоответствие типов". Отладчик показывал, что Объект.Товары имеет тип ДанныеФормыКоллекция.

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

Функции РеквизитФормыВЗначение() и ДанныеФормыВЗначение() предназначены для преобразования данных формы (таких как реквизиты формы или их элементы) в соответствующие им объекты конфигурации или значения. Например, они могут преобразовать реквизит формы типа ДанныеФормыЭлемент, представляющий собой ссылку на справочник, в саму ссылку или объект справочника. Однако они не предназначены для прямого преобразования ДанныеФормыКоллекция в ТаблицуЗначений. Попытка сделать это приводит к ошибке несоответствия типов, поскольку ДанныеФормыКоллекция не является ни ТабличнойЧастьюОбъекта, ни ТаблицейЗначений, и у этих функций нет прямого механизма для такого преобразования.

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


// Эти попытки приводили к ошибке "Несоответствие типов"
ТЗ = РеквизитФормыВЗначение(Объект.Товары, Тип("ТаблицаЗначений"));
ТЗ = РеквизитФормыВЗначение(Объект.Товары.Выгрузить, Тип("ТаблицаЗначений")); // Здесь ошибка, т.к. .Выгрузить - это метод, а не свойство
ТЗ = РеквизитФормыВЗначение("Объект.Товары", Тип("ТаблицаЗначений"));
ТЗ = ДанныеФормыВЗначение(Объект.Товары, Тип("ТаблицаЗначений"));
ТЗ = ДанныеФормыВЗначение(Объект.Товары.Выгрузить, Тип("ТаблицаЗначений")); // Аналогично
ТЗ = ДанныеФормыВЗначение("Объект.Товары", Тип("ТаблицаЗначений"));

Как мы видим, основная причина ошибок кроется в неправильном использовании функций для преобразования типа ДанныеФормыКоллекция.

Прямое и наиболее эффективное решение: метод "Выгрузить()"

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

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

Рассмотрим пример использования:


// Получаем табличную часть формы
// В данном случае, Объект.Товары - это реквизит формы типа ДанныеФормыКоллекция
ДанныеФормыТабличнаяЧасть = Объект.Товары;

// Преобразуем ее в ТаблицуЗначений с помощью метода Выгрузить()
ТаблицаЗначенийТовары = ДанныеФормыТабличнаяЧасть.Выгрузить();

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

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


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

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

// Пример из форума с указанием колонок:
ТаблицаЗначенийТоварыСпец = Объект.Товары.Выгрузить(, "АлкогольнаяПродукция, ИдентификаторСтроки, Количество, НомерСтроки");

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

Передача табличной части в запрос

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

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

Рассмотрим, как это делается, хотя для автоматизации переноса данных без программирования можно использовать One RPA:

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

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


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

// Пример 2: Отдельная переменная для ТаблицыЗначений
ТоварыТЗ = Объект.Товары.Выгрузить();
Запрос = Новый Запрос;
Запрос.Параметры.Вставить("ТаблицаТовары", ТоварыТЗ);
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТаблицаТовары.Номенклатура,
    |    ТаблицаТовары.Количество
    |ИЗ
    |    &ТаблицаТовары КАК ТаблицаТовары";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

// Пример 3: Прямая установка выгруженной ТЧ в параметр
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТоварыДокумента", Объект.Товары.Выгрузить());
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТоварыДокумента.Номенклатура,
    |    СУММА(ТоварыДокумента.Количество) КАК ОбщееКоличество
    |ИЗ
    |    &ТоварыДокумента КАК ТоварыДокумента
    |СГРУППИРОВАТЬ ПО
    |    ТоварыДокумента.Номенклатура";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

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

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

Сравнение подходов и рекомендации

Рассмотрим, в каких случаях какой подход следует применять:

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

Наша рекомендация: Всегда начинайте с самого простого решения. Если ваша задача — просто получить табличную часть формы в виде ТаблицыЗначений, используйте ТЗ = Объект.Товары.Выгрузить();. Этот подход является стандартом де-факто и в подавляющем большинстве случаев будет именно тем, что вам нужно. Только если требуется сложная серверная обработка с другими данными базы или агрегацией, рассмотрите вариант с запросом, но помните, что выгрузка в ТЗ все равно будет первым шагом.

Дополнительные нюансы

Мы хотим дополнительно уточнить разницу между ДанныеФормыКоллекция и ТабличнаяЧастьОбъекта, поскольку это часто вызывает путаницу.

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

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

← На главную