Почему реквизиты формы в 1С:Предприятии 8.3 требуют РеквизитФормыВЗначение для обработки на сервере?

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

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

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

Суть проблемы: Реквизиты формы и их типы в 1С

Давайте посмотрим на ситуацию, когда мы сталкиваемся с тем, что часть реквизитов формы доступна нам сразу по имени, а часть – нет. Это не случайно, и причина кроется в том, как платформа 1С управляет данными на управляемых формах.

Прямой доступ к простым реквизитам.

Рассмотрим реквизиты формы с простыми типами, такими как Строка, Число, Булево, Дата или ссылочные типы (например, СправочникСсылка.Номенклатура). Эти реквизиты, как правило, доступны напрямую в модуле формы. Мы можем обращаться к ним по их имени, например, МойРеквизитФормыСтрока, и получать или устанавливать их значения непосредственно. Это происходит потому, что их значения легко сериализуются – то есть могут быть просто преобразованы в текстовый формат для передачи, а затем восстановлены. Платформа без труда передает такие данные между клиентом и сервером, что позволяет нам работать с ними без дополнительных преобразований как в клиентском, так и в серверном контексте модуля формы.

Косвенный доступ к сложным реквизитам: ДеревоЗначений и ТаблицаЗначений.

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

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

Методы РеквизитФормыВЗначение и ЗначениеВРеквизитФормы: Мост между формой и объектом

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

Назначение РеквизитФормыВЗначение.

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

Отличие от ПолучитьОбъект().

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

Когда необходимо использовать РеквизитФормыВЗначение?

Мы используем этот метод в следующих основных случаях:

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

Метод ЗначениеВРеквизитФормы.

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

"Оболочки" данных формы: ДанныеФормыКоллекция и ДанныеФормыДерево

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

Механизм представления данных.

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

Ограничения "оболочек".

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

Контекст выполнения в модуле формы: Клиент и Сервер

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

Директивы компиляции.

В модуле формы мы можем использовать директивы &НаКлиенте, &НаСервере и &НаСервереБезКонтекста для указания, где будет выполняться определенный фрагмент кода:

Передача данных между Клиентом и Сервером.

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

Именно в контексте серверного выполнения (&НаСервере) и становится доступен метод РеквизитФормыВЗначение, так как он требует полный контекст формы для преобразования ее "оболочек" в прикладные объекты.

Основной реквизит формы: Автоматизация процессов

Существует один особый вид реквизита формы, который заслуживает отдельного внимания – это основной реквизит формы.

Роль основного реквизита.

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

При открытии формы платформа автоматически преобразует данные из прикладного объекта (который был получен из базы данных) в данные формы, заполняя все связанные с ним реквизиты. Аналогично, при попытке записи документа или элемента справочника, платформа автоматически преобразует данные из формы обратно в прикладной объект и сохраняет его в базу данных.

Доступ к свойствам основного реквизита.

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

Пример практического использования РеквизитФормыВЗначение

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


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

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

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

    // Шаг 4: Обрабатываем найденные строки.
    Если МассивНайденныхСтрок.Количество() > 0 Тогда
        Сообщить("Найдены строки в дереве по заданному условию:");
        Для Каждого СтрокаДЗ Из МассивНайденныхСтрок Цикл
            // Предположим, у строки есть поле "Описание"
            Сообщить("  - Код: " + СтрокаДЗ.Код + ", Наименование: " + СтрокаДЗ.Наименование + ", Описание: " + СтрокаДЗ.Описание);
            // Если нужно, можем изменить найденные строки. Например:
            // СтрокаДЗ.Статус = "Обработано";
        КонецЦикла;
    Иначе
        Сообщить("Строки по заданному условию не найдены в дереве.");
    КонецЕсли;

    // Шаг 5 (опционально): Если были внесены изменения в ДеревоДляОбработки
    // (например, мы изменили значения полей в найденных строках),
    // и эти изменения нужно отобразить на форме, используем ЗначениеВРеквизитФормы.
    // ЗначениеВРеквизитФормы(ДеревоДляОбработки, "МоеДеревоДанных");
    // В данном примере мы только читаем, поэтому обратное преобразование не требуется.
КонецПроцедуры

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

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

← На главную