Почему возникает ошибка «Переменная не определена» в модуле менеджера документа при использовании консоли запросов в обычном приложении 1С?

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

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

Выясним причину: особенности компиляции в обычном приложении

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

  1. Режим тонкого клиента (управляемые формы): В этом режиме модули менеджеров компилируются исключительно на стороне сервера. Клиентское приложение не имеет к ним прямого доступа, и все вызовы происходят через серверный контекст.
  2. Режим толстого клиента (обычное приложение): Здесь логика кардинально меняется. Модули менеджеров компилируются одновременно в двух контекстах — и на сервере, и на клиенте. Это сделано для обеспечения совместимости и поддержки работы традиционных интерактивных механизмов обычных форм.

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

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

Способ 1. Изменение свойств общего модуля (быстрое решение)

Самый простой и быстрый способ решить проблему — изменить настройки видимости общего модуля, к которому идет обращение. Разберем по шагам, как это сделать в конфигураторе:

  1. Найдем в дереве метаданных конфигурации нужный общий модуль (в нашем примере это ElasticSearchПовтИсп).
  2. Откроем палитру свойств этого модуля.
  3. Установим флажок «Вызов сервера» (Server Call) в дополнение к уже установленному флажку «Сервер». Также можно убедиться, что включены флажки «Клиент (обычное приложение)» или «Внешнее соединение», если планируется использование модуля в этих средах.

Включение свойства «Вызов сервера» сообщает клиентскому компилятору, что имя модуля корректно и к нему можно обращаться из клиентского контекста. При компиляции кода на клиенте платформа понимает, что данный модуль физически исполняется на сервере, но доступен для вызова. Ошибка компиляции исчезает, и консоль запросов начинает успешно работать.

Однако такое решение, хоть и устраняет видимый симптом, имеет существенные архитектурные недостатки с точки зрения стандартов разработки 1С.

Способ 2. Использование инструкций препроцессора (рекомендуемый подход)

Если наш общий модуль (в данном примере ElasticSearchПовтИсп) является модулем с повторным использованием возвращаемых значений (кэширующим модулем), предоставление ему доступа через «Вызов сервера» крайне нежелательно. Кэширование на клиенте при вызовах сервера работает неэффективно, так как каждый вызов с клиента на сервер все равно инициирует сетевой трафик (round-trip) для проверки актуальности кэша на сервере.

Чтобы исключить непроизводительные вызовы и сделать код чистым, рассмотрим более корректный подход. Мы должны сделать так, чтобы клиентский компилятор при проверке модуля менеджера вообще игнорировал серверный код. Для этого применим инструкции препроцессора #Если... Тогда.

Разберем пример правильного оформления кода в модуле менеджера документа:


#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

Процедура ЗаписатьЛогЭкспорта(ДокументСсылка) Экспорт
    // Вызываем серверный кэширующий модуль без риска ошибок на клиенте
    АдресРесурса = ElasticSearchПовтИсп.Префикс();
    // Дальнейшая логика отправки данных...
КонецПроцедуры

#КонецЕсли

При таком подходе, когда консоль запросов в обычном приложении запускает компиляцию модуля менеджера на стороне клиента, препроцессор видит условия компиляции и полностью вырезает данный блок кода из клиентского контекста. Компилятор клиента просто «не видит» вызов ElasticSearchПовтИсп.Префикс(), следовательно, никаких ошибок о неопределенной переменной не возникает.

Важный нюанс: обработка получения представления объекта

Проанализируем важную деталь, которую необходимо учитывать при полном оборачивании модулей менеджеров в инструкции препроцессора. В модулях менеджеров часто переопределяют стандартные обработчики событий получения представления данных, такие как ОбработкаПолученияПредставления и ОбработкаПолученияПолейПредставления.

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

Если вы обернете абсолютно весь код модуля менеджера в директиву #Если Сервер Тогда, эти обработчики перестанут работать на клиенте. Система вернется к стандартному формированию представлений (например, будет выводить просто «Наименование» или «Номер от даты»), игнорируя ваш уникальный алгоритм. Чтобы избежать этого, проектируйте структуру модуля менеджера следующим образом:


// Эту часть оставляем доступной для всех контекстов (включая клиент)
Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    Представление = "Документ " + Данные.Номер + " от " + Формат(Данные.Дата, "ДФ=dd.MM.yyyy");
КонецПроцедуры

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

// Весь остальной тяжелый серверный код и интеграционные процедуры изолируем внутри препроцессора
Процедура ВыгрузитьВElasticSearch() Экспорт
    АдресРесурса = ElasticSearchПовтИсп.Префикс();
    // Реализация выгрузки
КонецПроцедуры

#КонецЕсли

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

← На главную