Почему не записываются данные в регистр сведений, подчиненный регистратору, в обработке проведения?

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

Разберем классическую ситуацию, с которой сталкиваются многие разработчики 1С. Казалось бы, стоит обыкновеннейшая задача: программно создать запись в свой регистр сведений, который подчинен регистратору. Мы пишем код, проверяем отладчиком — все необходимые данные присутствуют, ошибок нет, но в базе записей не появляется. То ли лыжи не едут, то ли мы что-то упускаем. Давайте подробно проанализируем эту проблему и выясним причину такого поведения платформы.

Анализ проблемного кода

Посмотрим на пример кода, который часто пишут по привычке, опираясь на общие статьи из интернета:


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

На первый взгляд, все логично: создали набор, установили отбор по регистратору, заполнили данные в цикле и вызвали метод Записать(). Если этот код запустить из внешней обработки, он отработает корректно. Но проблема кроется в том, что этот код выполняется внутри модуля документа, а именно в процедуре ОбработкаПроведения.

Почему созданный набор записей «затирается»?

Выясним причину такого поведения. В модуле проведения документа уже существует встроенный объект для работы с записями — это коллекция Движения. Когда мы используем СоздатьНаборЗаписей(), мы создаем в оперативной памяти отдельный, независимый объект.

Рассмотрим по шагам, что происходит в платформе:

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

В результате в базу записывается девственно чистый набор записей, затирая все наши ручные манипуляции. Игра одновременно с двумя объектами (коллекцией документа и независимым набором) ни к чему хорошему не приводит.

Как правильно записывать движения в обработке проведения

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

Посмотрим на корректный вариант кода:


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

В данном случае платформа сама оптимизирует процесс: физическая запись в базу данных произойдет только после выхода из процедуры ОбработкаПроведения, но до завершения транзакции. Это минимизирует количество обращений к СУБД и снижает риск возникновения взаимных блокировок (deadlocks).

Особенности механизма автоматической записи движений

Рассмотрим подробнее внутренние механизмы платформы «1С:Предприятие», чтобы закрепить понимание:

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

Когда метод СоздатьНаборЗаписей все-таки нужен?

Хотя в модуле документа его использовать нельзя, этот метод остается единственно верным в следующих ситуациях:

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

← На главную