При разработке прикладных решений в 1С часто возникает задача логирования или переноса данных в архивный регистр в момент удаления записи. Однако у регистров сведений в платформе 1С:Предприятие отсутствует прямое событие ПередУдалением в модуле объекта, в отличие от справочников или документов. Рассмотрим особенности механизма записи регистров сведений и разберем способы корректного перехвата удаления данных как в формах, так и на уровне базы данных.
Проанализируем, как платформа работает с записями регистра. В 1С любая модификация данных регистра сведений — будь то изменение значений ресурсов, добавление новой строки или удаление существующей — на низком уровне выполняется через объект РегистрСведенийНаборЗаписей. При этом действуют следующие правила:
ПередУдалением или ПриУдалении на уровне модуля набора записей.Замещать = Истина. При редактировании старые данные удаляются, а новые записываются. При удалении записывается пустой набор записей по заданному отбору.Разберем самый простой вариант, когда удаление инициируется пользователем через интерфейс формы записи. Если в конфигурации переопределена или программно вызывается команда удаления, мы можем выполнить перенос данных непосредственно перед вызовом метода Удалить().
Посмотрим на пример реализации в модуле формы записи:
// Процедура обработки интерактивной команды удаления
Процедура ДействиеУдалитьЗапись()
// 1. Сохраняем текущие данные в архивный регистр
НаборАрхива = РегистрыСведений.АрхивЗаписей.СоздатьНаборЗаписей();
НаборАрхива.Отбор.Период.Установить(ЭтотОбъект.Период);
НаборАрхива.Отбор.Организация.Установить(ЭтотОбъект.Организация);
НоваяЗапись = НаборАрхива.Добавить();
ЗаполнитьЗначенияСвойств(НоваяЗапись, ЭтотОбъект);
НоваяЗапись.ДатаАрхивации = ТекущаяДата();
НаборАрхива.Записать();
// 2. Вызываем стандартный метод удаления текущей записи
ЭтотОбъект.Удалить();
КонецПроцедуры
Важно: Этот способ подходит только для изоляции конкретного пользовательского сценария в обычной форме. Если пользователь нажмет клавишу Delete в форме списка регистра, этот код не выполнится.
Если требуется контролировать интерактивное удаление записей пользователем из таблицы списка, воспользуемся обработчиком события табличного поля ПередУдалением. Разберем по шагам, как это работает:
ПередУдалением(Отказ) табличного поля получаем коллекцию удаляемых строк (выделенных пользователем).Отказ = Ложь) либо отменяем действие при ошибке.Рассмотрим пример кода для формы списка регистра:
Процедура РегистрСведенийСписокПередУдалением(Элемент, Отказ)
Для Каждого Строка Из Элемент.ВыделенныеСтроки Цикл
// Создаем запись в логе или архивном регистре
МенеджерАрхива = РегистрыСведений.ИсторияУдалений.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(МенеджерАрхива, Строка);
МенеджерАрхива.ДатаУдаления = ТекущаяДата();
МенеджерАрхива.Пользователь = ПараметрыСеанса.ТекущийПользователь;
Попытка
МенеджерАрхива.Записать();
Исключение
Отказ = Истина;
ВызватьИсключение "Не удалось зафиксировать удаление в архиве: " + ОписаниеОшибки();
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Проанализируем наиболее надежный системный подход. Чтобы перехватывать удаление записей при любых операциях (интерактивных, программных, обменах данными), логику переносят в обработчик ПередЗаписью модуля набора записей (РегистрСведенийНаборЗаписей) или в соответствующую подписку на события.
Алгоритм определения удаляемых записей:
Замещать в значение Истина.Прочитать().ЭтотОбъект.ЭтотОбъект.Количество() = 0 при замещении), являются удаляемыми.Посмотрим на пример кода в модуле набора записей:
Процедура ПередЗаписью(Отказ, Замещать)
// Перехватываем только замещение существующих данных
Если Не Замещать Тогда
Возврат;
КонецЕсли;
// Считываем текущие данные из базы до их перезаписи
СтарыйНабор = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
Для Каждого ЭлементОтбора Из ЭтотОбъект.Отбор Цикл
Если ЭлементОтбора.Использование Тогда
СтарыйНабор.Отбор[ЭлементОтбора.Имя].Установить(ЭлементОтбора.Значение);
КонецЕсли;
КонецЦикла;
СтарыйНабор.Прочитать();
// Если в базе были записи, а новый набор пустой — происходит удаление
Если СтарыйНабор.Количество() > 0 И ЭтотОбъект.Количество() = 0 Тогда
Для Каждого УдаляемаяЗапись Из СтарыйНабор Цикл
МенеджерАрхива = РегистрыСведений.АрхивЦен.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(МенеджерАрхива, УдаляемаяЗапись);
МенеджерАрхива.ДатаАрхивации = ТекущаяДата();
МенеджерАрхива.Записать();
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Такой подход обеспечивает целостность учета и гарантирует, что ни одна запись не будет удалена без фиксации в архивном регистре.