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

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

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

Анализ проблемы: почему поведение одного и того же кода различается

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


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

// Заполним таблицу движений
ОбщегоНазначения.ЗагрузитьВТаблицуЗначений(ТаблицаПоТоварам, ТаблицаДвижений);

// Недостающие поля
Инд = 0;
Для каждого Строка Из ТаблицаДвижений Цикл
    Инд = Инд + 1;
    Строка.НомерСтрокиДокумента = Инд;
КонецЦикла;

ТаблицаДвижений.ЗаполнитьЗначения(Дата, "Период");
ТаблицаДвижений.ЗаполнитьЗначения(Ссылка, "Регистратор");
ТаблицаДвижений.ЗаполнитьЗначения(Истина, "Активность");

НаборДвижений.мПериод = Дата;
НаборДвижений.мТаблицаДвижений = ТаблицаДвижений;

Если Не Отказ Тогда
    Движения.СписанныеТовары.ВыполнитьДвижения();
КонецЕсли;

В первом документе этот фрагмент отрабатывает штатно: платформа автоматически сохраняет набор записей в базу данных. Во втором документе при том же коде движений нет, но если в конце написать НаборДвижений.Записать(), строки появляются. Выясним причину такого расхождения: всё дело в метаданных и правилах работы платформы с коллекцией Движения.

Причина 1: Свойство документа «Запись движений при проведении»

Главный фактор, определяющий поведение платформы при завершении транзакции проведения, — свойство объекта метаданных Запись движений при проведении (вкладка «Движения» документа). Оно может принимать одно из двух значений:

  1. Записывать модифицированные — платформа отслеживает изменения в коллекциях наборов записей. Если в процессе проведения набор записей регистра изменялся (в него добавлялись строки или вызывались модифицирующие методы), платформа автоматически установит признак необходимости записи и сохранит данные в СУБД перед фиксацией транзакции.
  2. Записывать выбранные — автоматическая запись наборов по признаку модифицированности отключается. Платформа запишет только те наборы, у которых явно взведен системный флаг Записывать = Истина.

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

Варианты правильного решения

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

Способ 1. Изменение свойства метаданных документа

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

  1. Откроем дерево метаданных и найдем нужный документ.
  2. Перейдем в окно свойств документа на закладку Движения.
  3. В поле Запись движений при проведении выберем значение Записывать модифицированные.

Способ 2. Программное управление свойством «Записывать»

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

Движения.СписанныеТовары.Записывать = Истина;

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

Почему не рекомендуется вызывать Метод Записать() вручную внутри проведения

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

  1. Лишние операции и риск двойной записи: если у документа позже изменится настройка метаданных или в коде будет выставлен флаг Записывать = Истина, платформа запишет набор записей повторно при выходе из процедуры проведения, что приведет к дублированию операций ввода-вывода к СУБД.
  2. Ранние блокировки и взаимоблокировки (дедлоки): метод Записать() накладывает блокировки на таблицы СУБД в момент его выполнения. Чем раньше заблокированы таблицы регистра внутри транзакции, тем дольше они удерживаются и тем выше вероятность возникновения дедлоков при параллельной работе пользователей. Стандарт разработки 1С предписывает формировать все движения в памяти, а запись делегировать платформе на финальном этапе проведения.
  3. Проблемы контроля ошибок: при ручном вызове записи в блоках обработки исключений можно случайно скрыть реальную ошибку СУБД, оставив документ в несогласованном состоянии.

Важные нюансы работы с подчиненными регистрами сведений

Работая с движениями подчиненных регистраторов, обратим внимание еще на несколько важных моментов:

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