В практике разработки на платформе 1С часто возникает задача: при создании нового документа пользователем необходимо не просто открыть форму, а предварительно запросить у него некие уточняющие данные (через вспомогательную форму) и сразу при первой записи документа зафиксировать эти данные в регистре сведений, который подчинен этому документу. Основная сложность заключается в том, что у нового документа еще нет ссылки в базе данных, а для записи в подчиненный регистр ссылка (регистратор) критически важна.
В рамках этой статьи мы подробно разберем, как грамотно реализовать этот механизм, рассмотрим архитектурные нюансы и проанализируем различные подходы, от работы с коллекцией Движения до манипуляций с уникальными идентификаторами.
Если документ в метаданных указан как регистратор для регистра сведений, платформа автоматически создает для него коллекцию Движения. Самый чистый и правильный с точки зрения транзакционности способ — это использование этой коллекции непосредственно в модуле объекта документа. Даже если документ не является «проводимым» в классическом понимании (у него отключено проведение), он все равно может делать записи в регистры при сохранении.
Рассмотрим алгоритм действий:
ПередЗаписью или ПриЗаписи.Записывать = Истина для соответствующего набора записей.Посмотрим на пример кода в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем наличие данных, переданных из формы через дополнительные свойства
Если ДополнительныеСвойства.Свойство("ДанныеРегистра") Тогда
Набор = Движения.СведенияОВариантах;
Набор.Записывать = Истина;
НоваяЗапись = Набор.Добавить();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Регистратор = ЭтотОбъект.Ссылка;
НоваяЗапись.Вариант = ДополнительныеСвойства.ДанныеРегистра;
КонецЕсли;
КонецПроцедуры
Этот метод хорош тем, что запись в регистр происходит в той же транзакции, что и запись самого документа. Если произойдет сбой при записи документа, данные в регистр также не попадут, что гарантирует целостность базы данных.
Часто разработчики переживают, что «ссылки еще нет», и поэтому пытаются сначала записать пустой документ, а потом обновлять его. Это плохая практика, порождающая лишние действия в БД. Платформа 1С позволяет получить ссылку для нового объекта еще до того, как он будет записан на диск.
Для этого в форме документа (или в обработке заполнения) можно использовать метод УстановитьСсылкуНового(). Разберем по шагам, как это работает:
Пример программного кода:
// В коде, который создает документ (например, в команде создания)
НовыйДок = Документы.НашДокумент.СоздатьОбъект();
НоваяСсылка = Документы.НашДокумент.ПолучитьСсылку(Новый УникальныйИдентификатор());
НовыйДок.УстановитьСсылкуНового(НоваяСсылка);
// Теперь НоваяСсылка — это полноценная ссылка, которую можно передать
// в измерения регистра сведений еще до вызова метода Записать()
Важный нюанс: если вы используете этот метод и передаете ссылку в регистр, но пользователь нажмет «Отмена» в форме документа, в регистре может остаться запись с «битой» ссылкой (Объект не найден), если вы записывали регистр независимым набором записей вне транзакции документа. Поэтому всегда старайтесь привязывать запись регистра к транзакции записи регистратора.
Проанализируем ситуацию, когда данные для регистра выбираются в отдельной форме перед созданием документа. Как передать их в модуль объекта, не создавая лишних реквизитов в самом документе? Для этого идеально подходит структура ДополнительныеСвойства.
Рассмотрим последовательность действий:
ДополнительныеСвойства объекта.В форме документа на сервере это выглядит так:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Если это новый документ и переданы параметры
Если Объект.Ссылка.Пустая() И Параметры.Свойство("ВыбранныйВариант") Тогда
// Помещаем данные в объект, чтобы они уехали на сервер при записи
ДокОбъект = РеквизитВЗначение("Объект");
ДокОбъект.ДополнительныеСвойства.Вставить("ДанныеРегистра", Параметры.ВыбранныйВариант);
ЗначениеВРеквизит(ДокОбъект, "Объект");
КонецЕсли;
КонецПроцедуры
Теперь при нажатии кнопки «Записать» данные будут доступны в модуле объекта в процедуре ПриЗаписи, где мы и выполним наполнение регистра, как описано в первом варианте.
Выясним причину, по которой иногда стоит отказаться от табличных частей в пользу прямого редактирования регистра. В типовых конфигурациях (например, БП 3.0) документ ОперацияБух не имеет табличной части для проводок. Вместо этого на форму выведен набор записей регистра бухгалтерии.
Мы можем поступить так же:
Движения.ИмяВашегоРегистра.Движения.Проанализируем ситуацию с точки зрения долгосрочной поддержки кода. Если вы боитесь, что структура регистра будет часто меняться и вам придется переделывать множество документов, использование подчиненного регистра — это правильный ход. Однако помните о следующих правилах:
НаборЗаписей.Записать() в коде формы, если это не обосновано специфической логикой.ОбработкаПроверкиЗаполнения в документе, чтобы убедиться, что данные для регистра корректны.ПередУдалением.Таким образом, самым надежным и современным способом является сочетание передачи параметров через ДополнительныеСвойства и управление записью через коллекцию Движения в модуле объекта с установкой флага Записывать = Истина.