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