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