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

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

При разработке конфигураций 1С разработчики иногда сталкиваются со странным поведением: при изменении значений ресурсов в модуле набора записей регистра накопления отладчик показывает корректно заполненные данные, однако после завершения процедуры и выхода в режим «1С:Предприятие» в базе данных остаются старые или нулевые значения.

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

Причины сброса значений ресурсов

Проанализируем механику работы платформы 1С при записи набора записей регистра накопления. Выделяются следующие основные причины, по которым внесенные изменения не попадают в базу данных:

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

Способ 1. Перенос логики в событие ПередЗаписью

Разберем самое простое и правильное решение, если заполнение ресурсов выполняется непосредственно в модуле набора записей регистра накопления. Изменение значений ресурсов необходимо выполнять в событии ПередЗаписью, до отправки данных в СУБД.

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


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

Значения, установленные в обработчике ПередЗаписью, гарантированно попадают в итоговый SQL-запрос платформы и сохраняются в физических таблицах информационной базы.

Способ 2. Заполнение ресурсов через коллекцию Движения документа

Если ресурс регистра должен рассчитываться или заполняться при проведении документа, наиболее надежный подход — заполнять его прямо в модуле документа-регистратора (в процедуре ОбработкаПроведения) или в подписке на событие ОбработкаПроведения документа.

Посмотрим на пример заполнения движения в модуле документа:


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

Способ 3. Использование автономного набора записей для корректировки

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

Рассмотрим пример внешней корректировки набора записей:


НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);

// Считываем текущие записи из базы данных
НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл
	Запись.Количество = 2;
КонецЦикла;

// Выполняем явную запись измененного набора
НаборЗаписей.Записать();

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

← На главную