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

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При программной работе с регистрами сведений в платформе 1С:Предприятие разработчики нередко сталкиваются с ситуацией, когда код создания набора записей отрабатывает без явных синтаксических ошибок, но новые строки в регистре так и не появляются. Разберем типичные причины такого поведения на примере регистра сведений ЦеныАТТ в конфигурации «Управление торговлей 10.3» и рассмотрим правильные варианты реализации записи.

Анализ типового фрагмента кода

Рассмотрим исходный фрагмент кода, вызвавший затруднение:


НаборЗаписей = РегистрыСведений.ЦеныАТТ.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Ссылка);

НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = Дата;
НоваяЗапись.Склад = СтрокаСклад.Склад; 
НоваяЗапись.Номенклатура = СтрокаПроверки.Номенклатура; 
НоваяЗапись.ХарактеристикаНоменклатуры = "";
НоваяЗапись.Цена = СтрокаПроверки.Цена;

НаборЗаписей.Записать();

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

Причина 1. Несоответствие типов данных в измерениях регистра

Обратим внимание на строку заполнения характеристики:

НоваяЗапись.ХарактеристикаНоменклатуры = "";

В типовых конфигурациях (включая «1С:Управление торговлей 10.3») измерение ХарактеристикаНоменклатуры имеет ссылочный тип данных — СправочникСсылка.ХарактеристикиНоменклатуры. Передача пустой строки "" в строго типизированное поле недопустима. В зависимости от режима базы данных и платформы это может привести либо к тихой ошибке приведения типов, либо к тому, что запись с некорректным значением не будет отображаться в стандартных запросах конфигурации, которые ожидают пустую ссылку.

Для корректного указания пустого значения ссылки используем предопределенный метод:


НоваяЗапись.ХарактеристикаНоменклатуры = Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка();

Причина 2. Контекст проведения документа и перезапись платформой

Выясним, где именно выполняется этот код. Если алгоритм вызывается внутри обработчика проведения документа (например, в процедуре ОбработкаПроведения модуля объекта), то непосредственная запись через РегистрыСведений.ЦеныАТТ.СоздатьНаборЗаписей() вступит в конфликт с механизмом проведения документа.

При проведении документа платформа 1С автоматически управляет его движениями. Если в момент проведения записать набор вручную, платформа в конце транзакции проведения всё равно перезапишет движения регистратора тем содержимым, которое находится в коллекции Движения документа. Если коллекция Движения.ЦеныАТТ не была заполнена в коде, платформа просто сотрет созданные вручную записи.

Разберем правильный вариант формирования движений внутри модуля документа:


Движение = Движения.ЦеныАТТ.Добавить();
Движение.Период = Дата;
Движение.Склад = СтрокаСклад.Склад;
Движение.Номенклатура = СтрокаПроверки.Номенклатура;
Движение.ХарактеристикаНоменклатуры = Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка();
Движение.Цена = СтрокаПроверки.Цена;

// Указываем платформе необходимость сохранения набора при проведении
Движения.ЦеныАТТ.Записывать = Истина;

Причина 3. Замещение набора и отсутствие предварительного чтения

По умолчанию метод НаборЗаписей.Записать() вызывается с параметром Замещать = Истина. Это означает, что платформа полностью заменяет все существующие в базе данных записи по данному регистратору теми строками, которые находятся в текущем наборе в оперативной памяти.

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

Для сохранения существующих записей используем следующий шаблон:


НаборЗаписей = РегистрыСведений.ЦеныАТТ.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Ссылка);

// Сначала считываем существующие данные из базы
НаборЗаписей.Прочитать();

// Добавляем новую запись к прочитанным
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = Дата;
НоваяЗапись.Склад = СтрокаСклад.Склад; 
НоваяЗапись.Номенклатура = СтрокаПроверки.Номенклатура; 
НоваяЗапись.ХарактеристикаНоменклатуры = Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка();
НоваяЗапись.Цена = СтрокаПроверки.Цена;

// Записываем набор с замещением прочитанного и дополненного состава
НаборЗаписей.Записать(Истина);

Причина 4. Влияние обработчиков модуля набора записей

Проанализируем структуру регистра сведений на уровне метаданных. У набора записей регистра есть собственный модуль. В нем могут быть определены события, такие как ПередЗаписью.

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

Причина 5. Статус документа и валидность ссылки

Для подчиненных регистров сведений критически важно состояние документа, ссылка которого передается в отбор:

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

Чек-лист для проверки и устранения проблемы

Разберем по шагам, как локализовать проблему при отладке:

  1. Проверяем тип значения переменной Ссылка. Убеждаемся, что это ссылка на существующий и уже сохраненный в базе документ.
  2. Убеждаемся, что в дереве метаданных документ выбран в качестве регистратора для регистра сведений ЦеныАТТ.
  3. Заменяем пустые строки на вызовы ПустаяСсылка() для всех ссылочных измерений.
  4. Проверяем точку вызова кода: если это проведение — переписываем логику на обращение к коллекции Движения документа.
  5. Ставим точку останова в модуль набора записей в процедуру ПередЗаписью, чтобы исключить программный отказ от записи.
← На главную