Как проверить ЭтоНовый() в событии ПриЗаписи для записанного объекта?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникает задача выполнить определенные действия только в момент первого создания объекта (документа или справочника). Однако, если логика требует наличия ссылки на уже записанный объект, мы вынуждены использовать событие ПриЗаписи. Здесь мы сталкиваемся с парадоксом: в момент события ПриЗаписи объект уже находится в базе данных, и метод ЭтоНовый() гарантированно возвращает Ложь.

Разберем подробно, как обойти это ограничение, используя стандартные механизмы платформы, и рассмотрим правильный архитектурный подход к решению этой задачи.

Суть проблемы

Когда вы записываете новый объект, платформа вызывает события в определенном порядке. Упрощенно цепочка выглядит так:

  1. ПередЗаписью — объект еще не в базе (если это первое создание), метод ЭтоНовый() возвращает Истина.
  2. Физическая запись в таблицы базы данных.
  3. ПриЗаписи — объект уже записан, у него есть ссылка, но метод ЭтоНовый() возвращает Ложь.

Автор вопроса столкнулся с необходимостью выполнять код в подписке на событие ПриЗаписи (так как ему нужна заполненная ссылка на документ), но только в том случае, если этот документ создается впервые. Прямой вызов проверки новизны в этом событии бесполезен.

Неверные подходы

Прежде чем перейти к правильному решению, рассмотрим, почему некоторые интуитивные варианты не работают.

1. Проверка на пустую ссылку

Многие пытаются проверить новизну через конструкцию:


Если Объект.Ссылка.Пустая() Тогда
    // Это новый?
КонецЕсли;

В событии ПриЗаписи ссылка у объекта уже всегда заполнена, поэтому такая проверка всегда вернет Ложь. Более того, даже в событии ПередЗаписью ссылка может быть уже заполнена (если она была установлена программно методом УстановитьСсылкуНового()), но объект при этом физически в базе еще отсутствует.

2. Добавление реквизита в метаданные

Добавлять в структуру документа реквизит типа «ЭтоБылНовый» — архитектурная ошибка. Это избыточные данные, которые увеличивают размер таблиц базы и усложняют обновление конфигурации. Мы должны решать задачу в рамках оперативной памяти текущей сессии.

Правильное решение: использование ДополнительныхСвойств

Самый надежный и стандартный способ (используемый в том числе в Библиотеке Стандартных Подсистем) — это передача состояния объекта между событиями через коллекцию ДополнительныеСвойства.

Свойство ДополнительныеСвойства — это структура, которая существует в оперативной памяти в рамках жизни объекта 1С. Она не сохраняется в базу данных, но сохраняется между вызовами ПередЗаписью и ПриЗаписи, так как это один и тот же экземпляр программного объекта.

Алгоритм реализации

Решение разбивается на два этапа (или две подписки на события):

  1. В обработчике ПередЗаписью мы проверяем, является ли объект новым, и сохраняем этот признак во временную структуру.
  2. В обработчике ПриЗаписи мы читаем этот признак.

Рассмотрим пример кода для модуля объекта или подписки на событие.

Этап 1: Запоминаем состояние перед записью


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Проверяем, является ли объект новым, пока он еще не записан
    Если ЭтоНовый() Тогда
        // Вставляем флаг в коллекцию ДополнительныеСвойства
        // Ключ "ЭтоНовыйОбъект" может быть любым понятным вам строковым идентификатором
        ДополнительныеСвойства.Вставить("ЭтоНовыйОбъект", Истина);
    КонецЕсли;

КонецПроцедуры

Этап 2: Читаем состояние после записи


Процедура ПриЗаписи(Отказ)
    
    // Пытаемся получить наше свойство
    ЯвляетсяНовым = Ложь;
    
    // Используем метод Свойство, чтобы не получить ошибку, если ключа нет
    ДополнительныеСвойства.Свойство("ЭтоНовыйОбъект", ЯвляетсяНовым);
    
    // Теперь переменная ЯвляетсяНовым содержит Истина, 
    // только если мы установили это в событии ПередЗаписью
    Если ЯвляетсяНовым Тогда
        // Здесь ссылка уже есть, и мы знаем, что это было первичное создание
        СсылкаНаОбъект = Ссылка;
        
        // Выполняем необходимую логику
        ЗарегистрироватьСозданиеЗаказа(СсылкаНаОбъект);
    КонецЕсли;

КонецПроцедуры

Важные нюансы

При реализации данного механизма необходимо учитывать несколько важных моментов, чтобы код работал корректно в любых ситуациях.

1. Обмен данными (РИБ)

Если в вашей базе настроен обмен данными, документы могут появляться в базе не только действия пользователя, но и при загрузке из другой базы. Технически для этой базы это будет ЭтоНовый() = Истина, но логически это старый документ, пришедший по обмену. Обычно бизнес-логику для таких объектов выполнять не нужно.

Поэтому проверка должна быть чуть сложнее:


Если ЭтоНовый() И Не ОбменДанными.Загрузка Тогда
    ДополнительныеСвойства.Вставить("ЭтоНовыйОбъект", Истина);
КонецЕсли;

2. Работа в типовых конфигурациях (БСП)

Если вы работаете с современными типовыми конфигурациями (ERP, УТ 11, КА, Бухгалтерия 3.0), механизмы БСП часто уже делают эту работу за вас. Во многих подписках на события в ДополнительныеСвойства автоматически помещаются параметры записи.

Например, в некоторых конфигурациях можно встретить вызовы общего модуля ОбщегоНазначенияУТ или ПроведениеДокументов, которые подготавливают свойства. Однако, наиболее безопасным путем остается явная установка своего флага, как показано в примере выше, так как это гарантирует независимость от изменений типового кода.

Резюме

Для определения факта новизны документа в событии ПриЗаписи:

  1. Не используйте проверки ЭтоНовый() или Ссылка.Пустая() непосредственно в событии ПриЗаписи.
  2. Используйте пару событий: ПередЗаписью для фиксации состояния и ПриЗаписи для обработки.
  3. Передавайте информацию через структуру ДополнительныеСвойства.
  4. Не забывайте исключать режим ОбменДанными.Загрузка, если это требуется логикой задачи.
← На главную