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

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

В практике разработки на платформе 1С:Предприятие одной из самых частых и при этом запутанных проблем является ситуация, когда программный код по записи в регистр сведений вроде бы отрабатывает без ошибок, отладчик показывает наличие записей в наборе, но после завершения транзакции данные в регистре так и не появляются. Особенно часто это происходит при работе с регистрами, имеющими режим записи «Подчинение регистратору».

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

Проблема использования СоздатьНаборЗаписей внутри проведения

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

Когда мы работаем внутри модуля документа в процедуре проведения, у документа уже существует коллекция Движения. Если регистр сведений указан в списке движений документа, платформа берет управление этим регистром на себя. Проанализируем, что происходит в этот момент:

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

Именно поэтому использование СоздатьНаборЗаписей внутри модуля проведения считается плохим тоном и часто ведет к потере данных. Выясним, как сделать это правильно.

Правильный подход: работа через коллекцию Движения

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // 1. Указываем, что данный регистр должен быть записан платформой
    Движения.Эксперт_ОбластьДействияАкцийПоСериямНоменклатуры.Записывать = Истина;
    
    // 2. Очищать набор явно не нужно, если стоит автоудаление движений в свойствах документа
    // Но если нужно перезаполнить программно, можно вызвать Очистить()
    Движения.Эксперт_ОбластьДействияАкцийПоСериямНоменклатуры.Очистить();
    
    // 3. Заполняем движения из табличной части
    Для Каждого СтрокаТЧ Из ТЧ_АкцииПоНоменклатуре Цикл
        НоваяЗапись = Движения.Эксперт_ОбластьДействияАкцийПоСериямНоменклатуры.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяЗапись, СтрокаТЧ);
        
        // Не забываем про обязательные поля, такие как Период (если регистр периодический) 
        // и активность (по умолчанию Истина, но лучше контролировать)
        НоваяЗапись.Период = Дата;
        НоваяЗапись.Активность = Истина;
        // Регистратор подставится автоматически!
    КонецЦикла;

КонецПроцедуры

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

Использование метода Загрузить() для ТЗ

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

Проанализируем ситуацию: у нас есть ТаблицаОбластиДействия. Чтобы данные «прижились», выполним следующие шаги:

  1. Убедимся, что имена колонок в ТаблицаЗначений полностью совпадают с именами измерений и ресурсов регистра.
  2. Убедимся, что типы данных в колонках соответствуют типам в регистре.
  3. Применим следующий код:

ТаблицаОбластиДействия = ЭтотОбъект.ТЧ_АкцииПоНоменклатуре.Выгрузить();
// Добавляем технические колонки, если их нет в ТЧ, но они есть в регистре
Если ТаблицаОбластиДействия.Колонки.Найти("Период") = Неопределено Тогда
    ТаблицаОбластиДействия.Колонки.Добавить("Период", Новый ОписаниеТипов("Дата"));
КонецЕсли;
ТаблицаОбластиДействия.ЗаполнитьЗначения(ЭтотОбъект.Дата, "Период");

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

Важно: Метод Загрузить() полностью замещает текущее содержимое коллекции в памяти. Если вы сначала добавили записи в цикле, а потом вызвали Загрузить(), записи из цикла будут удалены.

Почему записи есть в базе, но их не видно в интерфейсе?

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

  1. Стандартные команды: В свойствах регистра сведений на закладке «Команды» должен стоять флаг «Использовать стандартные команды». Если он снят, платформа не будет автоматически отображать переход к записям регистра из панели навигации формы документа.
  2. Активность записей: Если в регистре есть поле Активность и оно программно установлено в Ложь, записи могут скрываться стандартными отборами списков.
  3. Права доступа (RLS): Проверьте, не настроены ли ограничения прав доступа на уровне записей. Возможно, под вашей учетной записью данные просто не должны быть видны по определенным условиям.
  4. Отборы в форме: Проверьте, нет ли в динамическом списке, через который вы смотрите данные, предустановленных фильтров, которые отсекают новые записи.

Транзакционная целостность и Отказ

Разберем еще одну неочевидную причину «исчезновения» данных. Поскольку запись движений происходит внутри транзакции проведения, любое событие, устанавливающее параметр Отказ = Истина, приведет к откату всей транзакции.

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

Рекомендации по отладке

Если вы зашли в тупик, воспользуйтесь проверенным алгоритмом действий:

Соблюдение этих правил и использование коллекции Движения вместо ручного создания наборов записей позволит вам избежать большинства проблем с «исчезающими» данными и обеспечит стабильную работу системы.

← На главную