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