Почему не сохраняются данные в регистре сведений при записи номенклатуры из подписки на событие?

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

При разработке механизмов фиксации системных событий нередко возникает задача сохранить сопутствующие данные в регистр сведений непосредственно в момент записи элемента справочника. Типичный сценарий — фиксация даты создания новой позиции справочника Номенклатура в типовом регистре ЗначенияСвойствОбъектов через подписку на событие ПриЗаписи.

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

Анализ проблемы и механизма работы формы

Рассмотрим типовой фрагмент кода, вызывающий затруднение:


МенЗап = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
МенЗап.Объект = Источник.Ссылка;
МенЗап.Свойство = СвойствоДатаСоздания;
МенЗап.Значение = ТекущаяДата();
МенЗап.Записать();

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

Выясним причину такого поведения. В типовых конфигурациях при интерактивном редактировании номенклатуры форма элемента считывает весь пул дополнительных реквизитов и сведений в оперативную память при открытии. В процессе сохранения элемента форма сама выполняет запись регистра через НаборЗаписей с установленным отбором по объекту и параметром замещения Записать(Истина).

События развиваются в следующем порядке:

  1. Пользователь нажимает кнопку сохранения в форме.
  2. Стартует транзакция записи объекта. Выполняется подписка ПриЗаписи, и менеджер записи успешно добавляет строку в регистр сведений.
  3. Управление возвращается в серверные процедуры формы. Форма формирует свой собственный набор записей на основе данных, находившихся на форме в момент редактирования (где нашей новой записи еще не было).
  4. Форма выполняет запись набора с замещением, тем самым полностью затирая запись, созданную в подписке.

Также обратим внимание на распространенное заблуждение: вызывать метод Прочитать() у объекта МенеджерЗаписи перед присвоением значений не требуется. Менеджер записи при установке ключевых измерений и вызове Записать(Истина) самостоятельно перезаписывает существующую запись или создает новую, если совпадений по измерениям не найдено.

Способ 1. Использование расширения для перехвата событий формы

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

Подключим форму справочника Номенклатура в расширение и добавим обработчик с аннотацией &После:


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

В контексте процедуры ПослеЗаписиНаСервере типовой набор формы уже зафиксирован в базе данных, поэтому созданная менеджером запись останется нетронутой.

Способ 2. Заполнение табличной части объекта (механизмы БСП)

В большинстве современных конфигураций на базе Библиотеки Стандартных Подсистем (БСП) дополнительные реквизиты хранятся не отдельными независимыми записями, а в табличной части самого справочника ДополнительныеРеквизиты.

В этом случае надежнее использовать подписку на событие ПередЗаписью справочника. Проанализируем реализацию:


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

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

Способ 3. Использование программного интерфейса БСП

Если свойство настроено именно как дополнительное сведение, правильным архитектурным подходом является вызов методов подсистемы УправлениеСвойствами. Подсистема корректно управляет блокировками и кэшированием данных:


УправлениеСвойствами.ЗаписатьСвойство(
    Источник.Ссылка,
    СвойствоДатаСоздания,
    ТекущаяДатаСеанса()
);

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

Альтернативные варианты хранения даты создания

Фиксация даты создания через регистр сведений — не единственный и зачастую избыточный путь. Рассмотрим альтернативы:

  1. Добавление реквизита через расширение конфигурации. В расширении можно добавить собственный реквизит ДатаСоздания напрямую в справочник Номенклатура. В событии ПередЗаписью при условии Источник.ЭтоНовый() реквизит заполняется датой сеанса. Это исключает лишние соединения таблиц и обращения к регистрам.
  2. Механизм «История данных» платформы. Начиная с платформы 8.3.11, для справочника можно включить встроенную историю данных. Платформа фиксирует точное время создания первой версии и автора автоматически.
  3. Подсистема версионирования БСП. При включении версионирования для номенклатуры дата первой записи гарантированно сохраняется в регистре сведений ВерсииОбъектов.

Важное предостережение: на форумах встречается совет извлекать дату создания из ссылки объекта через метод УникальныйИдентификатор(). Следует помнить, что генерация даты на основе GUID работает только для идентификаторов версии 1, сформированных сервером «1С:Предприятие». Если номенклатура загружается через внешние интеграции, EnterpriseData, веб-сервисы или создается с предопределенным GUID версии 4, такой способ вернет неверное значение.

← На главную