Как из процедуры на клиенте штатными средствами прочитать сразу все реквизиты ссылки без написания своей функции

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

Разработчики на платформе 1С:Предприятие 8.3 при переходе на управляемые формы неизбежно сталкиваются с архитектурным ограничением: на тонком и веб-клиенте невозможно напрямую обратиться к реквизитам объекта через точку от ссылки (например, конструкция СсылкаНаДоговор.Организация вызовет ошибку). Платформа требует, чтобы получение любых данных из базы выполнялось на стороне сервера.

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

Почему платформа запрещает обращение к реквизитам ссылки на клиенте?

Для того чтобы эффективно писать код, важно понимать физику процесса. Давайте проанализируем, что представляет собой объект типа «Ссылка» (например, СправочникСсылка.Контрагенты) на клиенте.

В тонком клиенте ссылка — это не сам объект базы данных с его многочисленными реквизитами, табличными частями и движениями. Ссылка на клиенте — это всего лишь очень легкий объект, содержащий:

  1. Уникальный идентификатор (UUID) — шестнадцатеричную строку, по которой запись идентифицируется в СУБД.
  2. Кэшированное представление объекта (как правило, наименование или код) для отображения пользователю в интерфейсе.

Самих данных (значений реквизитов) на клиенте физически нет. Если бы платформа разрешала неявное обращение через точку на клиенте, ей приходилось бы при каждом таком обращении отправлять скрытый синхронный запрос на сервер, дергать базу данных и возвращать результат. В масштабах корпоративной системы с сотнями пользователей это мгновенно убило бы производительность сети и сервера приложений. Поэтому разработчики платформы сделали это ограничение жестким и явным.

Опасность «ручного» получения реквизитов на сервере через точку

Рассмотрим типичную ошибку, которую совершают даже опытные разработчики, пытаясь быстро получить данные на сервере. В модуле формы пишется следующий код:


&НаСервереБезКонтекста
Функция ПолучитьРеквизитыНаСервере(СсылкаНаКонтрагента)
    Результат = Новый Структура;
    Результат.Вставить("ИНН", СсылкаНаКонтрагента.ИНН);
    Результат.Вставить("КПП", СсылкаНаКонтрагента.КПП);
    Возврат Результат;
EndФункции

Выясним причину, почему такой подход считается серьезной ошибкой оптимизации. Когда мы пишем СсылкаНаКонтрагента.ИНН, платформа 1С выполняет неявное считывание всего объекта целиком из базы данных в оперативную память сервера приложений. Если у вашего справочника несколько десятков реквизитов, тяжелые табличные части или хранилища значений с прикрепленными файлами, сервер прочитает абсолютно все эти данные ради одного только ИНН.

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

Решение №1: Использование готовых модулей-вызовов сервера БСП

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

Основной модуль БСП ОбщегоНазначения является чисто серверным, и вызвать его напрямую с клиента нельзя. Однако разработчики 1С предусмотрели специальные модули-клиенты (так называемые «мосты» или «вызовы сервера»). В зависимости от используемой конфигурации, вы можете вызвать готовые функции прямо из клиентской процедуры без написания своего серверного кода:

Посмотрим на пример правильного вызова на клиенте:


&НаКлиенте
Процедура ПриИзмененииКонтрагента(Элемент)
    
    СсылкаНаОбъект = Объект.Контрагент;
    Если Не ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
        Возврат;
    КонецЕсли;
    
    // Передаем список нужных реквизитов через запятую
    СписокРеквизитов = "ИНН, КПП, ЮридическийАдрес, КодПоОКПО";
    
    // Вызываем штатную функцию БСП напрямую с клиента
    ДанныеКонтрагента = ОбщегоНазначенияУТВызовСервера.ЗначенияРеквизитовОбъекта(СсылкаНаОбъект, СписокРеквизитов);
    
    // Получаем структуру с готовыми значениями без лишней нагрузки на сервер
    ОрганизацияИНН = ДанныеКонтрагента.ИНН;
    ОрганизацияКПП = ДанныеКонтрагента.КПП;
    
КонецПроцедуры

Этот способ идеален. Функция ЗначенияРеквизитовОбъекта внутри себя строит динамический запрос к СУБД, который выбирает строго указанные поля. Никакого лишнего чтения объекта в память не происходит, а вызов осуществляется одной строчкой кода на клиенте.

Решение №2: Использование возможностей управляемой формы (без кода)

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

Разберем этот прием по шагам:

  1. Откройте редактор управляемой формы в конфигураторе.
  2. Перейдите на вкладку «Реквизиты».
  3. Найдите ваш реквизит формы, содержащий ссылку (например, Объект.Договор).
  4. Раскройте его по «плюсу». Платформа покажет древовидную структуру всех реквизитов этого договора, хранящихся в базе.
  5. Перетащите нужный реквизит (например, Объект.Договор.ДатаНачалаДействия) на дерево элементов формы.

Платформа сама создаст поле ввода или поле надписи. Теперь при выборе договора в форме система автоматически выполнит оптимизированный серверный запрос в фоне, получит дату договора и передаст ее на клиент. В коде на клиенте вы сможете мгновенно прочитать это значение, просто обратившись к свойству:


&НаКлиенте
Процедура ПроверитьДатуДоговора()
    // Данные уже кэшированы на клиенте благодаря элементу формы!
    Если Объект.Договор.ДатаНачалаДействия < ТекущаяДата() Тогда
        ПоказатьПредупреждение(, "Срок действия договора уже начался!");
    КонецЕсли;
КонецПроцедуры

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

Решение №3: Сбор данных при открытии формы

Если данные ссылки нужны вам не интерактивно в процессе работы, а сразу при инициализации экрана, лучшим архитектурным решением будет собрать всю необходимую информацию на сервере один раз в момент открытия.

Рекомендуется использовать процедуру ПриСозданииНаСервере. Мы можем подготовить структуру необходимых данных, поместить ее во временное хранилище или передать в параметры формы, чтобы на клиенте прочитать ее без дополнительных серверных вызовов:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Читаем нужные данные за один проход на сервере
    СтруктураПараметров = Новый Структура;
    СтруктураПараметров.Вставить("ВалютаУчета", Объект.Организация.ВалютаРегламентированногоУчета);
    
    // Передаем параметры на клиент через параметры формы или временные переменные
    Параметры.Установить("ДополнительныеДанные", СтруктураПараметров);
    
КонецПроцедуры

Решение №4: Проектирование собственного общего модуля «моста»

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

Не пишите функции получения реквизитов внутри модулей каждой отдельной управляемой формы. Сделайте один раз системный шаг:

  1. Создайте новый общий модуль с именем _ОбщегоНазначенияВызовСервера.
  2. Установите у него свойства: Клиент (управляемое приложение) и Вызов сервера.
  3. Напишите в нем универсальный ретранслятор для базовых функций БСП.

Пример кода для вашего нового общего модуля:


// Модуль: _ОбщегоНазначенияВызовСервера
// Свойства: Вызов сервера = Истина, Клиент = Истина

Функция ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита) Экспорт
    Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита);
КонецФункции

Функция ЗначенияРеквизитовОбъекта(Ссылка, Реквизиты) Экспорт
    Возврат ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, Реквизиты);
КонецФункции

Благодаря этому простому приему вы получите единую точку доступа к реквизитам любых ссылок прямо с клиента по всей конфигурации. Ваш код на клиенте в любой форме станет чистым и читаемым:


&НаКлиенте
Процедура КнопкаВыполнитьНажатие(Кнопка)
    Статус = _ОбщегоНазначенияВызовСервера.ЗначениеРеквизитаОбъекта(Объект.ДокументСсылка, "СтатусУтверждения");
КонецПроцедуры

Работа с предопределенными значениями на клиенте

Отдельно рассмотрим задачу получения предопределенных элементов (например, конкретных значений перечислений или предопределенных справочников). Начиная с версии платформы 8.3, для этого вообще не требуется обращаться к серверу.

Вы можете использовать штатную функцию платформы ПредопределенноеЗначение напрямую в клиентском коде:


&НаКлиенте
Процедура ПроверитьТипКонтрагента()
    
    // Получение значения перечисления на клиенте без вызова сервера!
    ЮрЛицо = ПредопределенноеЗначение("Перечисление.ЮридическоеФизическоеЛицо.ЮридическоеЛицо");
    
    Если Объект.ЮрФизЛицо = ЮрЛицо Тогда
        // Выполняем логику для ЮрЛица
    КонецЕсли;
    
КонецПроцедуры

Если в вашей системе используется БСП, рекомендуется вызывать функцию ПредопределенныйЭлемент из модуля ОбщегоНазначенияКлиент. Преимущество этого метода в том, что он возвращает Неопределено вместо вызова системной ошибки, если элемент не найден в базе данных. Кроме того, БСП автоматически кэширует результаты первого обращения, предотвращая избыточную нагрузку при повторных проверках.

Резюме

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

Использование этих подходов позволит вам писать производительный, чистый и надежный код, соответствующий стандартам разработки фирмы «1С».

← На главную