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