Как удалить битые записи «Объект не найден» в регистре накопления 1С

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

В процессе эксплуатации баз данных 1С специалисты часто сталкиваются с появлением так называемых «фантомных» или «битых» движений в регистрах накопления. В поле Регистратор таких записей отображается строка вида «Объект не найден (84:bf00001517a7000c11e4bf51a511391b)». Подобные ситуации обычно возникают из-за некорректной работы распределенных информационных баз (РИБ), сбоев при обмене данными, аппаратных сбоев на сервере или принудительного удаления документов без контроля ссылочной целостности.

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

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

Шаг 1: Как правильно найти битые записи с помощью запроса

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

Чтобы выявить подобные записи, мы воспользуемся особенностью работы платформы 1С с битыми ссылками. Если обратиться через точку к реквизиту битой ссылки (например, к свойству Ссылка), платформа вернет значение NULL. Напишем и выполним следующий запрос:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ДвиженияТоваров.Регистратор КАК Регистратор
ИЗ
    РегистрНакопления.ДвижениеТоваров КАК ДвиженияТоваров
ГДЕ
    НЕ ДвиженияТоваров.Регистратор ЕСТЬ NULL
    И ДвиженияТоваров.Регистратор.Ссылка ЕСТЬ NULL

Рассмотрим подробнее, почему это работает. Для существующего в базе документа конструкция Регистратор.Ссылка вернет саму ссылку на документ. Для удаленного документа (нашей битой ссылки) СУБД вернет значение NULL. Таким образом, этот запрос выведет список всех «мертвых» регистраторов, которые оставили движения в регистре накопления ДвижениеТоваров.

Шаг 2: Программная очистка движений и обход проверок

Самый очевидный способ избавиться от ненужных строк — программно создать набор записей, установить отбор по поврежденному регистратору, очистить его и записать. Однако при попытке сделать это напрямую разработчики часто сталкиваются с ошибками вида: «Поле "Распоряжение" не может быть пустым» или другими ошибками контроля заполнения реквизитов.

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

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


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

// Читать набор не обязательно, если наша цель — его полная очистка
// НаборЗаписей.Прочитать(); 

// Очищаем коллекцию движений
НаборЗаписей.Очистить();

// Устанавливаем признак загрузки данных, чтобы отключить проверки и подписки
НаборЗаписей.ОбменДанными.Загрузка = Истина;

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

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

Шаг 3: Восстановление документа по его исходному GUID (Рекомендуемый способ)

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

У любой битой ссылки есть свой уникальный идентификатор. Мы можем получить его программно и создать новый документ именно с этим идентификатором. Рассмотрим, как это реализовать:

  1. Получаем уникальный идентификатор из битой ссылки с помощью метода УникальныйИдентификатор().
  2. Генерируем новую ссылку для нужного типа документа на основании этого идентификатора с помощью метода ПолучитьСсылка().
  3. Создаем новый документ в кодовой базе и жестко привязываем его к полученной ссылке методом УстановитьСсылкуНового().
  4. Записываем документ в режиме обычной записи (без проведения).

Посмотрим на пример кода, реализующий этот алгоритм:


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

// Восстанавливаем ссылку для конкретного типа документа (например, Этап производства)
СсылкаНаНовыйДок = Документы.ЭтапПроизводства2_2.ПолучитьСсылка(Идентификатор);

// Создаем объект документа
НовыйДокумент = Документы.ЭтапПроизводства2_2.СоздатьДокумент();
НовыйДокумент.УстановитьСсылкуНового(СсылкаНаНовыйДок);

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

// Записываем документ в базу данных (без проведения!)
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);

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

Шаг 4: Почему битые записи «лезут» снова при закрытии месяца?

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

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

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

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

Шаг 5: Оптимизация итогов на крупных базах данных

Если ваша база данных имеет большой объем, а количество битых записей исчисляется тысячами, стандартная запись пустых наборов может вызвать длительные транзакции и серьезные блокировки таблиц СУБД. Это связано с тем, что платформа 1С при каждой записи набора будет пытаться пересчитать таблицы итогов регистров накопления.

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


// Отключаем использование итогов для ускорения записи наборов
РегистрыНакопления.ДвижениеТоваров.УстановитьИспользованиеИтогов(Ложь);

// [Здесь выполняем код удаления/очистки битых записей]

// Включаем использование итогов обратно
РегистрыНакопления.ДвижениеТоваров.УстановитьИспользованиеИтогов(Истина);

// Выполняем полный пересчет итогов регистра накопления
РегистрыНакопления.ДвижениеТоваров.ПересчитатьИтоги();

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

← На главную