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