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