а какие события у записываемого объекта ты знаешь? И их обработчики?
Обработчики - ПередЗаписью, ПриЗаписи.
Однако сходу непонятно, как в этих обработчиках обращаться к двум наборам данных - старому и новому, и возможно ли это вообще.
Кроме того, беглый поиск в интернете показал, что с записью все не очевидно. Например, что эти обработчики вызываются по два раза, а не по одному (см. тут).
Значение ресурса до записи можно получить запросом. "ПриЗаписи" в регистр определите изменилось ли значение ресурса и установите поле набора записей ВремяПоследнегоИзменения равным текущему времени.
(7) Всё равно есть "проблемки". Например, когда записывается выбранная запись менеджера записи или изменение происходит интерактивно через форму записи – сначала записывается пустой набор, затем измененный. Перед записью измененного набора в ИБ уже не будет "старой" версии.
Значение ресурса до записи можно получить запросом. "ПриЗаписи" в регистр определите изменилось ли значение ресурса
Честно говоря, я надеялся, что в 1С есть что-то наподобие триггера BEFORE INSERT из классических СУБД, где доступны одновременно старый и новый набор записей.
Ну что ж, придется тогда так, спасибо за подсказку.
(12) Можно попробовать обмануть платформу и перед записью пустого набора заполнять его записями из ИБ. (кажется, я даже видел такой костыль в типовой ЕРП). Только нужно как-то программно отличить запись пустого набора в случае изменения и в случае реального удаления.
Можно попробовать обмануть платформу и перед записью пустого набора заполнять его записями из ИБ. (кажется, я даже видел такой костыль в типовой ЕРП)
М-да... Похоже, по-другому действительно не получится (видимо, про то же писал тут lone_mayson).
Также полезную ссылку ниже привел gybson, продублирую ее тут:
Последовательность выполнения событий при записи в регистр сведений Попытка создать аналог классического триггера СУБД на запись - с одновременным доступом к старым и новым данным - привела к нерабочему варианту. Оставлю тут, чтобы потом не ходить заново тем же путем.
Суть решения заключалась в том, чтобы получить существующие данные записи регистра по измерениям с помощью метода менеджера записи регистра Получить() и сравнить их с новыми.
Это работало, если запись проводить программно.
А вот при записи из формы в пользовательском режиме возникли неполадки: Прочитать() стала заполнять запись пустыми значениями реквизитов. Видимо, это связано с предварительной вставкой пустой записи (о чем здесь неоднократно писали).
Появлением дополнительного вызова обработчика ПередИзменением() это объяснить не получается, т.к. он вызывается с пустым набором записей, и до вызова Прочитать() в этом случае вообще не должно доходить. Однако никаких других отличий не видно. Дальнейшая разработка по этому направлению зашла в тупик.
Ниже привожу код модуля набора записей регистра сведений:
Процедура ПередЗаписью(Отказ, Замещение)
// ЭтотОбъект - набор записей регистра
Сообщить("Вызван обработчик ПередЗаписью()");
N = 0;
Для каждого ЭлементНабораЗаписей Из ЭтотОбъект Цикл
N = N + 1;
Сообщить("Круг цикла № " + N);
ПередЗаписьюЭлемента(ЭлементНабораЗаписей);
КонецЦикла;
КонецПроцедуры
Процедура ПередЗаписьюЭлемента(ЭлементНабораЗаписей)
СуществующиеДанные = ПолучитьСуществующиеДанныеЗаписи(ЭлементНабораЗаписей, ЭтотОбъект);
Сообщить("Записываем элемент");
Если ОбновитьЛиВремяИзменения(ЭлементНабораЗаписей, СуществующиеДанные) Тогда
Сообщить("Обновляем время изменения");
ЭлементНабораЗаписей.ВремяПоследнегоИзменения = ТекущаяДата();
КонецЕсли;
КонецПроцедуры // ПередЗаписьюЭлемента()
Функция ОбновитьЛиВремяИзменения(НовыеДанные, СуществующиеДанные) Экспорт
Возврат НовыеДанные.Р <> СуществующиеДанные.Р;
КонецФункции // ОбновитьЛиВремяИзменения()
Функция ПолучитьСуществующиеДанныеЗаписи(ЭлементНабораЗаписей, МенеджерНабораЗаписейРегистра)
Копия = ПодготовитьДанныеДляПоискаЗаписи(ЭлементНабораЗаписей, МенеджерНабораЗаписейРегистра);
Копия.Прочитать();
Возврат Копия;
КонецФункции // ПолучитьТекущиеДанныеЗаписи()
Функция ПодготовитьДанныеДляПоискаЗаписи(ЭлементНабораЗаписей, МенеджерНабораЗаписейРегистра)
МетаданныеЗаписи = МенеджерНабораЗаписейРегистра.Метаданные();
ИмяРегистра = МетаданныеЗаписи.Имя;
Измерения = МетаданныеЗаписи.Измерения;
КопияЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи();
Для каждого Измерение Из Измерения Цикл
КопияЗаписи[Измерение.Имя] = ЭлементНабораЗаписей[Измерение.Имя];
КонецЦикла;
Возврат КопияЗаписи;
КонецФункции
(14)
Тут еще выяснилось, что при обновлении записи старая полностью стирается, и значения явно не указанных полей из неё не подхватываются. Т.е., в терминах классической СУБД происходит REPLACE, а не UPDATE.
А мне нужен как раз UPDATE. Значит, при использовании классического триггера, если бы он был, пришлось бы вдобавок устанавливать значения всем полям из данных старой записи.
Наверное, легче уж тогда просто сбоку подставить набор данных и сделать собственно обновление, а не вставку.
Регистр заполняется программно из одного места, так что в триггере тут необходимости нет, просто так было бы понадежнее.
Проверка изменения полей регистра сведений ПередЗаписью с использованием кеширования исходных данных через БСП (БуферОбмена).
Сложность в том, что при изменении данных регистра сведений сперва происходит запись пустого набора данных и когда записывается итоговый набор данных, прежние данные запросом уже не получить. Данный код кеширует прежние данные в первой итерации во временном хранилище и передает его адрес второй итерации через параметр сеанса (встроенными средствами БСП).
Вспомнилось, что в конфигурации ERP в модуле набора записей регистра Стоимость ОС, например, вроде бы вычисляют изменения движений документа в событиях ПередЗаписью и ПриЗаписи. В первом формируют временную таблицу на основании состояния таблицы регистра до записи, во втором - сравнивают исходные данные с новыми. Данные хранятся в дополнительных свойствах объекта.
upd: В данном случае, наверно, использовать только ПередЗаписью: сравнить прошлые записи по набору записей с ЭтотОбъект и изменить значение реквизита в наборе записей по необходимости