Как изменить или удалить записи регистра сведений, подчиненного регистратору, если регистратор утерян или поврежден?

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

При некорректном переносе данных между базами (например, при переходе с 1С 7.7 на 1С:Управление торговлей 8.3) нередко возникает нарушение ссылочной целостности. В результате в регистрах сведений появляются строки с надписью «Объект не найден» в измерениях или в поле регистратора. Если регистр сведений не подчинен регистратору, исправить ситуацию можно простой записью через РегистрСведенийМенеджерЗаписи. Однако для регистров с режимом записи «Подчинение регистратору» этот объект недоступен на уровне платформы. Единственный путь изменения данных — использование объекта РегистрСведенийНаборЗаписей с обязательным строгим отбором по документу-регистратору.

Разберем подробно, как программно найти и скорректировать такие «осиротевшие» записи, избежать типичных ошибок при работе со ссылками и перенести движения в документ ручной корректировки.

Причины проблемы и ограничения платформы

Проанализируем ситуацию: в регистре сведений ЦеныНоменклатуры для товаров без использования характеристик указаны несуществующие характеристики (битые ссылки). При этом сами документы установки цен в базе отсутствуют — ссылка на регистратор также отображается как <Объект не найден>.

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

  1. Тип пустой аналитики: если измерение имеет ссылочный тип (например, СправочникСсылка.ХарактеристикиНоменклатуры), нельзя присваивать ему значение Неопределено. Корректное пустое значение — Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка().
  2. Обращение к полям набора: измерения и ресурсы принадлежат отдельной строке набора (ЗаписьНабора), а не самому объекту НаборЗаписей. Попытка прочитать НаборЗаписей.Номенклатура вызывает исключение «Поле объекта не обнаружено».
  3. Уникальность записей: замена битой характеристики на пустую ссылку может привести к дублированию ключа записи, если в рамках одного регистратора для этой номенклатуры уже присутствует запись без характеристики.

Способ 1. Получение битого регистратора через запрос и перенос в документ корректировки

Платформа 1С позволяет устанавливать битую ссылку в отбор набора записей. Это означает, что для очистки или перезаписи набора нам достаточно получить саму битую ссылку на регистратор. Выясним причину, почему это работает: ссылка существует как бинарный идентификатор (GUID) в таблице регистра, даже если объект в таблице документов физически отсутствует.

Чтобы отобрать регистраторы, которых нет в информационной базе, обратимся к их реквизитам через точку. Для несуществующего документа соединение с таблицей документа вернет NULL.

Рассмотрим по шагам реализацию алгоритма:

  1. Выбираем запросом уникальные ссылки на несуществующие регистраторы и периоды записей.
  2. Для каждого найденного регистратора создаем НаборЗаписей и устанавливаем отбор по битой ссылке.
  3. Считываем строки набора, очищаем битые характеристики, подставляя пустую ссылку.
  4. Выгружаем исправленные строки в таблицу значений и очищаем старый набор записей, удаляя битые движения из базы.
  5. Создаем документ КорректировкаЗаписейРегистров, в который переносим исправленные строки.

Посмотрим на пример законченного программного кода:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |	ЦеныНоменклатуры.Регистратор КАК Регистратор,
    |	ЦеныНоменклатуры.Период КАК Период
    |ИЗ
    |	РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
    |ГДЕ
    |	ЦеныНоменклатуры.Регистратор.Номер ЕСТЬ NULL";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

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

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

Способ 2. Восстановление документа-регистратора по исходному GUID

В некоторых случаях создавать отдельные документы ручной корректировки нежелательно — требуется сохранить исходный тип регистратора (например, УстановкаЦенНоменклатуры). Разберем, как восстановить документ по существующей битой ссылке, используя метод УстановитьСсылкуНового().

Рассмотрим пример восстановления связи:


// Получаем уникальный идентификатор битой ссылки регистратора
ИдентификаторРегистратора = Выборка.Регистратор.УникальныйИдентификатор();

// Формируем новую ссылку с тем же идентификатором
СсылкаНового = Документы.УстановкаЦенНоменклатуры.ПолучитьСсылку(ИдентификаторРегистратора);

// Создаем документ и привязываем ссылку
ДокументОбъект = Документы.УстановкаЦенНоменклатуры.СоздатьДокумент();
ДокументОбъект.УстановитьСсылкуНового(СсылкаНового);
ДокументОбъект.Дата = Выборка.Период;
ДокументОбъект.Записать();

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

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

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

Особенности проверки битых ссылок на характеристики

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


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

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

← На главную