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