Как правильно организовать запись в регистр при записи документа в 1С

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

В процессе разработки в среде 1С:Предприятие часто возникает задача: при записи документа необходимо внести изменения в определенный регистр (сведений или накопления). Особую сложность вызывает условие, когда запись должна происходить не всегда, а только при изменении конкретного реквизита. Рассмотрим подробно, почему запись напрямую из формы — это плохая практика, и разберем наиболее надежные способы реализации этой задачи в модуле объекта.

Почему не стоит писать в регистр из модуля формы

Прежде всего, разберем архитектурный аспект. Если мы размещаем логику записи в регистр в модуле формы (например, в процедуре ПриЗаписиНаСервере), мы привязываем бизнес-логику к интерфейсу. Это приводит к следующим проблемам:

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

Поэтому правильным местом для такой логики являются обработчики событий в модуле объекта.

Метод 1: Использование «ДополнительныхСвойств» и событий модуля объекта

Рассмотрим ситуацию, когда нам нужно записать данные в регистр только в том случае, если пользователь изменил реквизит Статус. Проблема заключается в том, что в процедуре ПриЗаписи данные уже изменены, и мы не знаем, каким было старое значение. В процедуре же ПередЗаписью у нас еще нет ссылки, если документ создается впервые.

Для решения мы используем связку двух событий и системную структуру ДополнительныеСвойства. Проанализируем алгоритм:

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

Посмотрим на пример кода в модуле объекта:


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

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

Метод 2: Работа с новыми объектами (УстановитьСсылкуНового)

Часто разработчики сталкиваются с ошибкой «Объект не найден» или отсутствием ссылки при попытке записать данные в регистр для только что созданного документа в процедуре ПередЗаписью. Выясним причину: физически записи в таблице базы данных еще нет, и ссылка еще не сформирована системой.

Чтобы получить ссылку до момента фактической записи, мы можем использовать метод УстановитьСсылкуНового(). Это позволяет нам заранее определить уникальный идентификатор будущего документа.

Рассмотрим, как это применить:


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

Метод 3: Использование набора записей для сложных случаев

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

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


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

Важные рекомендации по работе с транзакциями

При реализации записи в регистры внутри модуля объекта обязательно учитывайте параметр Отказ.

Процедура ПриЗаписи выполняется внутри транзакции. Это означает, что если вы установите Отказ = Истина в этой процедуре, изменения документа не будут сохранены в базе данных, и изменения в регистре (если они были сделаны в этой же транзакции) также будут отменены (откачены).

Основные правила:

Таким образом, использование событий модуля объекта в сочетании со структурой ДополнительныеСвойства является наиболее надежным и «чистым» способом решения задачи. Это гарантирует корректную работу системы как при ручном вводе данных пользователем, так и при автоматизированной обработке документов.

← На главную