При разработке в среде управляемых форм 1С начинающие разработчики часто сталкиваются с ситуацией: в форме документа выбрано ссылочное поле (например, Контрагент), и требуется программно получить связанные с ним данные — ИНН, КПП, юридический адрес или банковский счет. Попытка прямого обращения через точку на стороне клиента (Объект.Контрагент.ИНН) приводит к ошибке или возвращает пустое значение. Разберем, почему так происходит и как правильно извлекать реквизиты ссылочных объектов в современных конфигурациях.
В архитектуре управляемого приложения 1С действует строгое разделение логики на клиентскую и серверную части. На тонком и веб-клиенте тип СправочникСсылка представляет собой лишь компактный идентификатор (содержит только ссылку и представление для отображения в интерфейсе). Сами данные объекта в память клиентского приложения не загружаются.
Платформа намеренно блокирует разыменование ссылок (обращение через точку к реквизитам объекта) на клиенте. Если бы такое поведение было разрешено, каждое обращение вызывало бы неявный сетевой синхронный вызов сервера базы данных, что привело бы к серьезным зависаниям интерфейса пользователя. Следовательно, для получения любых дополнительных реквизитов необходимо обращаться к серверу.
Рассмотрим классический и наиболее производительный подход. Для получения данных мы создаем неконтекстную серверную функцию. Использование директивы &НаСервереБезКонтекста гарантирует, что на сервер не передается контекст всей формы (ее элементы и реквизиты), что экономит сетевой трафик и оперативную память.
Разберем по шагам реализацию процедуры:
Объект.Контрагент.Знач.Посмотрим на пример кода в модуле формы:
&НаКлиенте
Процедура ПроверитьИННКонтрагента(Команда)
Если ЗначениеЗаполнено(Объект.Контрагент) Тогда
ИНН = ПолучитьИННКонтрагентаНаСервере(Объект.Контрагент);
Сообщить("ИНН контрагента: " + ИНН);
Иначе
Сообщить("Контрагент не выбран!");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьИННКонтрагентаНаСервере(Знач СсылкаНаКонтрагента)
// На сервере разыменование ссылки через точку разрешено
Возврат СсылкаНаКонтрагента.ИНН;
КонецФункции
В типовых конфигурациях (таких как «1С:Бухгалтерия предприятия 3.0», «1С:ERP», «1С:Управление торговлей») широко используется Библиотека Стандартных Подсистем. В ней предусмотрен оптимизированный функционал для быстрого чтения данных объектов без создания лишних серверных процедур в самой форме.
Важный нюанс контекста общего модуля: общий модуль ОбщегоНазначения компилируется только на сервере. Если вызвать ОбщегоНазначения.ЗначениеРеквизитаОбъекта(...) прямо в процедуре с директивой &НаКлиенте, возникнет ошибка «Переменная не определена (ОбщегоНазначения)».
Для прямого вызова из клиентского кода в БСП существует специальный модуль с признаком клиентского вызова — ОбщегоНазначенияВызовСервера. Рассмотрим примеры его использования:
&НаКлиенте
Процедура ПолучитьРеквизитыЧерезБСП(Команда)
// Получение одного реквизита напрямую с клиента в одну строку
ИНН = ОбщегоНазначенияВызовСервера.ЗначениеРеквизитаОбъекта(Объект.Контрагент, "ИНН");
Сообщить("ИНН: " + ИНН);
// Если нужно получить сразу несколько реквизитов за один серверный вызов:
ДанныеКонтрагента = ОбщегоНазначенияВызовСервера.ЗначенияРеквизитовОбъекта(
Объект.Контрагент,
"ИНН, КПП, НаименованиеПолное"
);
Сообщить("ИНН: " + ДанныеКонтрагента.ИНН);
Сообщить("КПП: " + ДанныеКонтрагента.КПП);
Сообщить("Полное наименование: " + ДанныеКонтрагента.НаименованиеПолное);
КонецПроцедуры
Метод ЗначенияРеквизитовОбъекта выполняет единый легковесный запрос к базе данных и возвращает структуру с запрошенными полями, что значительно быстрее поштучного обращения.
Если значение (например, ИНН контрагента) требуется только для отображения в интерфейсе документа, писать код вообще не требуется. Платформа 1С умеет связывать реквизиты подчиненных объектов автоматически:
ТолькоПросмотр = Истина).Объект -> Контрагент -> выбираем ИНН (итоговый путь: Объект.Контрагент.ИНН).Платформа самостоятельно позаботится об оптимизированном отображении и обновлении значения при смене контрагента пользователем.
Проанализируем частую сложность: попытка получить юридический адрес или номер счета через простое обращение к реквизиту объекта (Контрагент.ЮридическийАдрес) завершится неудачей, так как эти данные в типовых конфигурациях не хранятся в основных реквизитах справочника.
КонтактнаяИнформация контрагента. Для ее получения на сервере используют методы модуля УправлениеКонтактнойИнформацией или запросы:
&НаСервереБезКонтекста
Функция ПолучитьЮридическийАдрес(Знач КонтрагентСсылка)
// Использование программного интерфейса БСП
Возврат УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(
КонтрагентСсылка,
Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента
);
КонецФункции
БанковскиеСчета. Ссылка на основной счет контрагента находится в реквизите ОсновнойБанковскийСчет. Получить его реквизиты на сервере можно через запрос либо через БСП:
&НаСервереБезКонтекста
Функция ПолучитьДанныеБанковскогоСчета(Знач КонтрагентСсылка)
СтруктураДанных = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
КонтрагентСсылка,
"ОсновнойБанковскийСчет.НомерСчета, ОсновнойБанковскийСчет.Банк.Наименование, ОсновнойБанковскийСчет.Банк.БИК"
);
Возврат СтруктураДанных;
КонецФункции
Разберем распространенную ошибку: попытку использовать метод формы РеквизитФормыВЗначение для чтения одиночных полей ссылки:
// НЕПРАВИЛЬНО: приведет к ошибке времени выполнения
&НаСервере
Функция ОшибочныйМетод()
Возврат РеквизитФормыВЗначение("Объект.Контрагент").ИНН;
КонецФункции
Метод РеквизитФормыВЗначение предназначен исключительно для преобразования основного реквизита формы целиком в объектную модель (например, из реквизита Объект типа ДанныеФормыСтруктура в полноценный ДокументОбъект для проведения или записи). Применение этого тяжелого метода для простого чтения полей ссылок нерационально и перегружает сервер.