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