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