Как поймать изменения при записи в регистр сведений?

1. 1234ru 15.03.25 21:49 Сейчас в теме
Есть вот такой регистр сведений:

- И1, И2 - измерения
- Р - ресурс
- ВремяПоследнегоИзменения - реквизит

При записи в регистр нужно определять, изменилось ли значение ресурса Р. Если изменилось, то обновлять ВремяПоследнегоИзменения.

Как это лучше сделать?
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
15. tusv 212 17.03.25 14:14 Сейчас в теме
(1) У объекта есть ДополнительныеСвойства тип Структура. Выгружаешь туда набор в событии перед записью и спокойно сравниваешь в ПриЗаписи
16. Sashares 33 17.03.25 14:44 Сейчас в теме
2. user2107191 15.03.25 23:22 Сейчас в теме
Ну а какие события у записываемого объекта ты знаешь? И их обработчики?
11. 1234ru 16.03.25 17:26 Сейчас в теме
(2)
а какие события у записываемого объекта ты знаешь? И их обработчики?

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

Вот и решил спросить у опытных людей.
3. gybson 16.03.25 00:30 Сейчас в теме
Значение ресурса до записи можно получить запросом. "ПриЗаписи" в регистр определите изменилось ли значение ресурса и установите поле набора записей ВремяПоследнегоИзменения равным текущему времени.
5. SlavaKron 16.03.25 09:09 Сейчас в теме
(3) ПриЗаписи набор уже записан в ИБ. Предлагаете дважды записывать набор?
7. gybson 16.03.25 16:34 Сейчас в теме
(5) Пусть будет "ПередЗаписью" суть сильно не меняется
9. SlavaKron 16.03.25 16:37 Сейчас в теме
(7) Всё равно есть "проблемки". Например, когда записывается выбранная запись менеджера записи или изменение происходит интерактивно через форму записи – сначала записывается пустой набор, затем измененный. Перед записью измененного набора в ИБ уже не будет "старой" версии.
10. gybson 16.03.25 16:50 Сейчас в теме
(9) Проблем, несомненно, много. Наверное даже код писать придется.
12. 1234ru 16.03.25 17:37 Сейчас в теме
(3)
Значение ресурса до записи можно получить запросом. "ПриЗаписи" в регистр определите изменилось ли значение ресурса

Честно говоря, я надеялся, что в 1С есть что-то наподобие триггера BEFORE INSERT из классических СУБД, где доступны одновременно старый и новый набор записей.

Ну что ж, придется тогда так, спасибо за подсказку.
13. SlavaKron 16.03.25 17:58 Сейчас в теме
(12) Можно попробовать обмануть платформу и перед записью пустого набора заполнять его записями из ИБ. (кажется, я даже видел такой костыль в типовой ЕРП). Только нужно как-то программно отличить запись пустого набора в случае изменения и в случае реального удаления.
17. 1234ru 17.03.25 18:14 Сейчас в теме
(13)
Можно попробовать обмануть платформу и перед записью пустого набора заполнять его записями из ИБ. (кажется, я даже видел такой костыль в типовой ЕРП)


М-да... Похоже, по-другому действительно не получится (видимо, про то же писал тут lone_mayson).

Также полезную ссылку ниже привел gybson, продублирую ее тут:
Последовательность выполнения событий при записи в регистр сведений
Попытка создать аналог классического триггера СУБД на запись - с одновременным доступом к старым и новым данным - привела к нерабочему варианту. Оставлю тут, чтобы потом не ходить заново тем же путем.

Суть решения заключалась в том, чтобы получить существующие данные записи регистра по измерениям с помощью метода менеджера записи регистра Получить() и сравнить их с новыми.

Это работало, если запись проводить программно.

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

Появлением дополнительного вызова обработчика ПередИзменением() это объяснить не получается, т.к. он вызывается с пустым набором записей, и до вызова Прочитать() в этом случае вообще не должно доходить. Однако никаких других отличий не видно. Дальнейшая разработка по этому направлению зашла в тупик.

Ниже привожу код модуля набора записей регистра сведений:

Процедура ПередЗаписью(Отказ, Замещение) 
	// ЭтотОбъект - набор записей регистра 
	Сообщить("Вызван обработчик ПередЗаписью()");
	N = 0;
	Для каждого ЭлементНабораЗаписей Из ЭтотОбъект Цикл 
		N = N + 1;       
		Сообщить("Круг цикла № " + N);
		ПередЗаписьюЭлемента(ЭлементНабораЗаписей); 
	КонецЦикла;
КонецПроцедуры              

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

Функция ОбновитьЛиВремяИзменения(НовыеДанные, СуществующиеДанные) Экспорт 
	Возврат НовыеДанные.Р <> СуществующиеДанные.Р;
КонецФункции // ОбновитьЛиВремяИзменения()  

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

Функция ПодготовитьДанныеДляПоискаЗаписи(ЭлементНабораЗаписей, МенеджерНабораЗаписейРегистра)
	МетаданныеЗаписи = МенеджерНабораЗаписейРегистра.Метаданные(); 
	ИмяРегистра = МетаданныеЗаписи.Имя; 
	Измерения = МетаданныеЗаписи.Измерения;
	КопияЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи(); 
	Для каждого Измерение Из Измерения Цикл
		КопияЗаписи[Измерение.Имя] = ЭлементНабораЗаписей[Измерение.Имя];
	КонецЦикла;	
	Возврат КопияЗаписи;
КонецФункции	
Показать


Пример программного обращения:
Запись = РегистрыСведений.ДляПроверкиКонтроляИзменений.СоздатьМенеджерЗаписи();     
Запись.И1 = "А";
Запись.И2 = "Б";              
Запись.Р = 1;   
Запись.Записать();


Также прилагаю изолированную конфигурацию для отладки и скриншоты, иллюстрирующие описанные шаги.
Прикрепленные файлы:
Конфигурация.zip
18. 1234ru 17.03.25 18:16 Сейчас в теме
(14)
Тут еще выяснилось, что при обновлении записи старая полностью стирается, и значения явно не указанных полей из неё не подхватываются. Т.е., в терминах классической СУБД происходит REPLACE, а не UPDATE.

А мне нужен как раз UPDATE. Значит, при использовании классического триггера, если бы он был, пришлось бы вдобавок устанавливать значения всем полям из данных старой записи.

Наверное, легче уж тогда просто сбоку подставить набор данных и сделать собственно обновление, а не вставку.

Регистр заполняется программно из одного места, так что в триггере тут необходимости нет, просто так было бы понадежнее.
20. SlavaKron 17.03.25 22:52 Сейчас в теме
(18)
Регистр заполняется программно из одного места
Тогда не стоит заморачиваться – проверяйте изменение ресурса в том же месте.
19. 1234ru 17.03.25 19:57 Сейчас в теме
(13)
Еще набрел на некое решение, использующее буфер обмена.

Уровень знаний мне не пока позволяет его осмыслить, поэтому оставляю тут ссылку, может, пригодится.

https://fastcode.im/Templates/7515

Проверка изменения полей регистра сведений ПередЗаписью с использованием кеширования исходных данных через БСП (БуферОбмена).
Сложность в том, что при изменении данных регистра сведений сперва происходит запись пустого набора данных и когда записывается итоговый набор данных, прежние данные запросом уже не получить. Данный код кеширует прежние данные в первой итерации во временном хранилище и передает его адрес второй итерации через параметр сеанса (встроенными средствами БСП).
14. gybson 16.03.25 18:23 Сейчас в теме
(12) Есть история данных, но надо копать теорию

Вот для примера
https://infostart.ru/1c/articles/1803149/?ysclid=m8bs8tiwx0449319327
https://infostart.ru/1c/tools/1882953/
4. lone_mayson 60 16.03.25 07:57 Сейчас в теме
Вспомнилось, что в конфигурации ERP в модуле набора записей регистра Стоимость ОС, например, вроде бы вычисляют изменения движений документа в событиях ПередЗаписью и ПриЗаписи. В первом формируют временную таблицу на основании состояния таблицы регистра до записи, во втором - сравнивают исходные данные с новыми. Данные хранятся в дополнительных свойствах объекта.
upd: В данном случае, наверно, использовать только ПередЗаписью: сравнить прошлые записи по набору записей с ЭтотОбъект и изменить значение реквизита в наборе записей по необходимости
6. user1936660 16.03.25 13:01 Сейчас в теме
(4)
только ПередЗаписью
А напомни, пожалуйста, порядок возникновение событий обработки записи с замещеним для регистра сведений. Для случая изменения и для случая удаления.
8. gybson 16.03.25 16:35 Сейчас в теме
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот