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

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

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

Причина 1. Незафиксированная транзакция при прерывании отладки

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

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

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

Причина 2. Ошибочный алгоритм очистки набора записей регистра

Нередко в коде можно встретить следующую избыточную конструкцию:


Набор = РегистрыНакопления.РасходыПоВидамДеятельности.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Ссылка);
Набор.Прочитать();
Набор.Очистить();
Набор.Записать(Истина);

Разберем по шагам, почему такой подход неэффективен:

  1. Метод Прочитать() выполняет лишнее обращение к базе данных, поднимая в оперативную память все текущие записи регистра по данному регистратору.
  2. Метод Очистить() очищает эту коллекцию в оперативной памяти сервера 1С.
  3. Метод Записать(Истина) перезаписывает набор пустыми данными.

Такой код создает лишнюю нагрузку на сервер 1С и СУБД. В платформе 1С набор записей сразу после создания и так является абсолютно пустым. Канонический и наиболее производительный способ полной очистки движений по регистратору выглядит следующим образом:


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

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

Очистка движений в контексте самого документа

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

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


Движения.РасходыПоВидамДеятельности.Записывать = Истина;
Движения.РасходыПоВидамДеятельности.Очистить();

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

Почему в движениях появляется «Объект не найден» и как это исправить

Часто попытка принудительно очистить регистр вызвана тем, что в движениях или отчетах видна битая ссылка (<Объект не найден...>), которая не уходит даже после повторного проведения. Как выясняется при детальном анализе, регистр здесь ни при чем — он является лишь отражением данных, которые формирует алгоритм проведения.

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

Рассмотрим основные способы устранения данной проблемы:

  1. Восстановление удаленного объекта по его GUID. Если известен уникальный идентификатор битой ссылки (его можно извлечь из строки вида <Объект не найден> (84:a284...)), мы можем программно создать новый элемент справочника с тем же самым идентификатором:
    
    НовыйИД = Новый УникальныйИдентификатор("4b3303cb-64bc-11ee-82c5-00155d012a01");
    СсылкаНаОбъект = Справочники.ВидыДеятельности.ПолучитьСсылку(НовыйИД);
    
    НовыйОбъект = Справочники.ВидыДеятельности.СоздатьЭлемент();
    НовыйОбъект.УстановитьСсылкуНового(СсылкаНаОбъект);
    НовыйОбъект.Наименование = "Восстановленный вид деятельности";
    НовыйОбъект.Записать();
    
    После записи элемента все битые ссылки в документах и регистрах автоматически начнут ссылаться на созданный объект без необходимости ручной корректировки каждого движения.
  2. Штатное тестирование и исправление. В режиме «Конфигуратор» запустим процедуру «Администрирование» — «Тестирование и исправление...», выберем пункт «Проверка ссылочной целостности информационной базы» и укажем действие при наличии неразрешимых ссылок: «Создавать объекты» или «Очищать ссылки».
  3. Программная проверка валидности ссылки перед проведением. Чтобы исключить запись некорректных данных в регистры, добавим в модуль документа проверку существования ссылочного объекта. Для битой ссылки метод ПолучитьОбъект() всегда возвращает Неопределено:
    
    Если ЗначениеЗаполнено(СтрокаТаблицы.ВидДеятельности) 
       И СтрокаТаблицы.ВидДеятельности.ПолучитьОбъект() = Неопределено Тогда
        
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
            "В строке указан несуществующий вид деятельности!", , "СтрокаТаблицы");
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    

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

← На главную