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