При работе с формами в 1С:Предприятии 8.3 программисты часто сталкиваются с необходимостью получить данные из табличной части, отображаемой на форме, в виде ТаблицыЗначений для дальнейшей программной обработки. Однако прямой перевод может вызвать сложности, особенно если не знать специфику работы с управляемыми формами. Рассмотрим эту проблему подробнее и выясним, как ее эффективно решить.
Начнем с анализа первоначальной проблемы, описанной автором темы. Автор пытался преобразовать табличную часть Объект.Товары в ТаблицуЗначений различными способами, используя функции РеквизитФормыВЗначение и ДанныеФормыВЗначение, но каждый раз получал ошибку "Несоответствие типов". Отладчик показывал, что Объект.Товары имеет тип ДанныеФормыКоллекция.
Эта ситуация абсолютно нормальна для управляемых форм. В контексте управляемой формы, реквизиты, которые представляют собой табличные части объекта (например, документа), не являются напрямую объектами типа ТабличнаяЧастьОбъекта или ТаблицаЗначений. Вместо этого они представляются как объекты типа ДанныеФормыКоллекция. Этот тип является специальным объектом, который связывает данные, отображаемые на форме, с базовым объектом конфигурации и обеспечивает их синхронизацию. Он служит "оберткой" для данных, позволяя форме отображать их и реагировать на изменения.
Функции РеквизитФормыВЗначение() и ДанныеФормыВЗначение() предназначены для преобразования данных формы (таких как реквизиты формы или их элементы) в соответствующие им объекты конфигурации или значения. Например, они могут преобразовать реквизит формы типа ДанныеФормыЭлемент, представляющий собой ссылку на справочник, в саму ссылку или объект справочника. Однако они не предназначены для прямого преобразования ДанныеФормыКоллекция в ТаблицуЗначений. Попытка сделать это приводит к ошибке несоответствия типов, поскольку ДанныеФормыКоллекция не является ни ТабличнойЧастьюОбъекта, ни ТаблицейЗначений, и у этих функций нет прямого механизма для такого преобразования.
Давайте посмотрим на примеры кода, которые вызывали ошибку у автора:
// Эти попытки приводили к ошибке "Несоответствие типов"
ТЗ = РеквизитФормыВЗначение(Объект.Товары, Тип("ТаблицаЗначений"));
ТЗ = РеквизитФормыВЗначение(Объект.Товары.Выгрузить, Тип("ТаблицаЗначений")); // Здесь ошибка, т.к. .Выгрузить - это метод, а не свойство
ТЗ = РеквизитФормыВЗначение("Объект.Товары", Тип("ТаблицаЗначений"));
ТЗ = ДанныеФормыВЗначение(Объект.Товары, Тип("ТаблицаЗначений"));
ТЗ = ДанныеФормыВЗначение(Объект.Товары.Выгрузить, Тип("ТаблицаЗначений")); // Аналогично
ТЗ = ДанныеФормыВЗначение("Объект.Товары", Тип("ТаблицаЗначений"));
Как мы видим, основная причина ошибок кроется в неправильном использовании функций для преобразования типа ДанныеФормыКоллекция.
Самый простой, правильный и распространенный способ получить ТаблицуЗначений из ДанныеФормыКоллекция — это использовать метод Выгрузить(), который предоставляется самим объектом ДанныеФормыКоллекция. Этот метод специально разработан для этой цели и позволяет получить копию данных табличной части в виде ТаблицыЗначений.
Когда вы вызываете метод Выгрузить() для объекта ДанныеФормыКоллекция, платформа 1С автоматически создает новую ТаблицуЗначений и заполняет ее всеми строками и колонками из табличной части, отображаемой на форме. При этом сохраняются имена колонок и типы данных.
Рассмотрим пример использования:
// Получаем табличную часть формы
// В данном случае, Объект.Товары - это реквизит формы типа ДанныеФормыКоллекция
ДанныеФормыТабличнаяЧасть = Объект.Товары;
// Преобразуем ее в ТаблицуЗначений с помощью метода Выгрузить()
ТаблицаЗначенийТовары = ДанныеФормыТабличнаяЧасть.Выгрузить();
// Теперь переменная ТаблицаЗначенийТовары имеет тип ТаблицаЗначений
// и содержит все данные из табличной части формы.
// Мы можем работать с ней как с обычной ТаблицейЗначений:
Для Каждого СтрокаТЗ Из ТаблицаЗначенийТовары Цикл
Сообщить("Номенклатура: " + СтрокаТЗ.Номенклатура + ", Количество: " + СтрокаТЗ.Количество);
КонецЦикла;
Мы также можем передать параметры в метод Выгрузить(), чтобы указать, какие колонки нам нужны. Это может быть полезно для оптимизации, если из табличной части требуется только часть колонок.
// Выгружаем только определенные колонки: Номенклатура, Количество, Цена
ТаблицаЗначенийТовары = Объект.Товары.Выгрузить(, "Номенклатура, Количество, Цена");
// Если нужно выгрузить только определенные строки, мы можем сначала отфильтровать их
// (хотя .Выгрузить() не имеет встроенного фильтра по строкам, это можно сделать после выгрузки
// или если есть необходимость отфильтровать ДанныеФормыКоллекция перед выгрузкой, это делается
// обычно через привязанную коллекцию или после выгрузки в ТЗ)
// Пример из форума с указанием колонок:
ТаблицаЗначенийТоварыСпец = Объект.Товары.Выгрузить(, "АлкогольнаяПродукция, ИдентификаторСтроки, Количество, НомерСтроки");
Использование метода Выгрузить() является наиболее эффективным и прямым способом решения задачи по преобразованию ДанныеФормыКоллекция в ТаблицуЗначений, когда нам нужна простая копия данных для дальнейшей обработки на стороне клиента или сервера 1С без обращения к базе данных для первичной выборки данных из уже имеющейся на форме коллекции.
В некоторых случаях нам может потребоваться не просто преобразовать табличную часть в ТаблицуЗначений, а выполнить более сложные операции с этими данными, которые лучше всего реализуются с помощью запросов к базе данных. Например, если нам нужно выполнить агрегацию, группировку, соединение с другими таблицами базы данных или фильтрацию по сложным условиям, запрос может быть более производительным и выразительным инструментом. Для удобного составления таких выборок можно использовать консоль запросов с продвинутым конструктором.
Однако, важно понимать, что для передачи данных из ДанныеФормыКоллекция в запрос, их все равно необходимо предварительно преобразовать в ТаблицуЗначений. Запросы 1С могут принимать в качестве параметров табличные значения (или табличные части объектов, но для формы это всегда будет выгрузка в ТЗ). Для отладки и проверки подобных конструкций подойдет инженерная консоль запросов для 1С.
Рассмотрим, как это делается, хотя для автоматизации переноса данных без программирования можно использовать One RPA:
ДанныеФормыКоллекция в ТаблицуЗначений, используя уже знакомый нам метод Выгрузить().ТаблицуЗначений как параметр запроса.Вот несколько примеров кода из обсуждения, демонстрирующих этот подход, в том числе для автоматизации обмена с ЕГАИС при учете алкогольной продукции:
// Пример 1: Выгрузка и установка как параметр
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Товары", Объект.Товары.Выгрузить(, "АлкогольнаяПродукция, ИдентификаторСтроки, Количество, НомерСтроки"));
Запрос.Текст =
"ВЫБРАТЬ
| Товары.АлкогольнаяПродукция,
| Товары.Количество
|ИЗ
| &Товары КАК Товары
|ГДЕ
| Товары.АлкогольнаяПродукция = ИСТИНА";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Пример 2: Отдельная переменная для ТаблицыЗначений
ТоварыТЗ = Объект.Товары.Выгрузить();
Запрос = Новый Запрос;
Запрос.Параметры.Вставить("ТаблицаТовары", ТоварыТЗ);
Запрос.Текст =
"ВЫБРАТЬ
| ТаблицаТовары.Номенклатура,
| ТаблицаТовары.Количество
|ИЗ
| &ТаблицаТовары КАК ТаблицаТовары";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Пример 3: Прямая установка выгруженной ТЧ в параметр
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТоварыДокумента", Объект.Товары.Выгрузить());
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыДокумента.Номенклатура,
| СУММА(ТоварыДокумента.Количество) КАК ОбщееКоличество
|ИЗ
| &ТоварыДокумента КАК ТоварыДокумента
|СГРУППИРОВАТЬ ПО
| ТоварыДокумента.Номенклатура";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Важно отметить, что использование запроса в данном контексте не отменяет необходимости выгрузить ДанныеФормыКоллекция в ТаблицуЗначений. Метод Выгрузить() все равно является первым шагом. Запрос лишь предоставляет дополнительный механизм для обработки уже выгруженных данных.
Пользователи в обсуждении справедливо отмечали, что использовать запрос только для того, чтобы получить ТаблицуЗначений, когда достаточно прямого вызова Выгрузить(), является избыточным и менее эффективным. Это создает ненужную нагрузку на SQL-сервер и увеличивает количество операций.
Рассмотрим, в каких случаях какой подход следует применять:
Объект.Товары.Выгрузить():
ТаблицыЗначений для дальнейшей обработки в коде (например, для перебора строк, внесения изменений, передачи в другую функцию) и не требуется сложная логика выборки или агрегации на стороне СУБД. Это самое быстрое и эффективное решение для получения ТЗ из ДанныеФормыКоллекция.ТаблицаЗначений:
ДанныеФормыКоллекция, а лишь использует выгруженную ТЗ как источник данных для дальнейшей обработки.Наша рекомендация: Всегда начинайте с самого простого решения. Если ваша задача — просто получить табличную часть формы в виде ТаблицыЗначений, используйте ТЗ = Объект.Товары.Выгрузить();. Этот подход является стандартом де-факто и в подавляющем большинстве случаев будет именно тем, что вам нужно. Только если требуется сложная серверная обработка с другими данными базы или агрегацией, рассмотрите вариант с запросом, но помните, что выгрузка в ТЗ все равно будет первым шагом.
Мы хотим дополнительно уточнить разницу между ДанныеФормыКоллекция и ТабличнаяЧастьОбъекта, поскольку это часто вызывает путаницу.
ДанныеФормыКоллекция:
Этот тип представляет табличную часть в контексте управляемой формы. Он является частью механизма обмена данными между формой и объектом конфигурации. Данные в ДанныеФормыКоллекция могут включать как уже сохраненные в базе данных строки, так и строки, добавленные или измененные пользователем, но еще не записанные в информационную базу. Именно из-за этой гибкости и связи с формой он не является непосредственно ТабличнойЧастьюОбъекта и требует специального метода Выгрузить() для получения копии в виде ТаблицыЗначений.
ТабличнаяЧастьОбъекта:
Этот тип представляет табличную часть непосредственно объекта базы данных (например, табличную часть документа или справочника). Доступ к нему обычно осуществляется через сам объект (например, ДокументОбъект.Товары). У ТабличнойЧастиОбъекта также есть метод Выгрузить(), который работает аналогично, возвращая ТаблицуЗначений. Если вы работаете с серверным кодом или с уже прочитанным из базы данных объектом, то будете иметь дело с ТабличнойЧастьюОбъекта.
В нашем случае, когда речь идет о "табличной части на форме", мы почти всегда имеем дело с ДанныеФормыКоллекция, и именно к ней применим рассмотренный метод Выгрузить().
Таким образом, мы рассмотрели различные подходы к преобразованию табличной части формы в таблицу значений в 1С:Предприятии 8.3. Мы выяснили, что наиболее прямой и эффективный способ – это использование метода Выгрузить() объекта ДанныеФормыКоллекция. Мы также разобрали, когда имеет смысл использовать запросы, и подчеркнули, что даже в этом случае метод Выгрузить() остается ключевым для подготовки данных. Надеемся, что этот подробный анализ поможет вам в вашей работе с 1С!