Как удалить «битый» элемент с нулевым GUID из регистрации изменений плана обмена?

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

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

Анализ проблемы: откуда берется «нулевой» GUID

Ситуация, когда в сообщении обмена появляется элемент с идентификатором 00000000-0000-0000-0000-000000000000, обычно свидетельствует о нарушении логической целостности базы данных. Разберем основные причины возникновения «фантомов»:

  1. Непосредственное удаление: Объект был удален из базы данных напрямую через СУБД или с помощью обработки, использующей метод Удалить() вместо пометки на удаление, при этом в таблице регистрации изменений (_ChngRec) осталась запись, ссылающаяся на уже несуществующий ID.
  2. Сбои транзакций: В момент записи объекта или регистрации изменений произошел критический сбой (обрыв питания, аварийное завершение процесса rphost), из-за чего запись в основной таблице не создалась, а в служебной таблице плана обмена — появилась.
  3. Ошибки платформы: В редких случаях при использовании сложных правил синхронизации или специфических настроек РИБ платформа может некорректно сформировать структуру сообщения.

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

Способ 1. Программная очистка регистрации по типу метаданных

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

Проанализируем пример кода, который позволяет очистить регистрацию для конкретного метаданного (например, Документ.РеализацияТоваровУслуг):


// Определяем узел, в котором возникла проблема
УзелОбмена = ПланыОбмена.СинхронизацияДанныхЧерезУниверсальныйФормат.НайтиПоКоду("001");

// Вместо передачи ссылки передаем объект метаданных
// Это очистит ВСЮ очередь изменений для данного типа документа по этому узлу
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, Метаданные.Документы.РеализацияТоваровУслуг);

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Реализация.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.РеализацияТоваровУслуг КАК Реализация
    |ГДЕ
    |   Реализация.Дата >= &НачалоПериода";

Запрос.УстановитьПараметр("НачалоПериода", '20230101');
Результат = Запрос.Выполнить().Выбрать();

Пока Результат.Следующий() Цикл
    ПланыОбмена.ЗарегистрироватьИзменения(УзелОбмена, Результат.Ссылка);
КонецЦикла;

Способ 2. Использование объекта УдалениеОбъекта

Если нам достоверно известно, что «фантом» — это результат удаления, мы можем попробовать передать в метод удаления регистрации специальный объект УдалениеОбъекта. Рассмотрим, как это работает программно:


// Создаем пустую ссылку нужного типа с нулевым GUID (или нужным битым GUID)
БитыйИдентификатор = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000");
БитыйОбъект = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(БитыйИдентификатор);

// Формируем объект удаления
ДанныеДляУдаления = Новый УдалениеОбъекта(БитыйОбъект);

// Пытаемся удалить регистрацию именно для этого "удаления"
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, ДанныеДляУдаления);

Важный момент: если GUID действительно состоит из одних нулей, платформа может не позволить создать УдалениеОбъекта стандартным способом. В этом случае перейдем к более радикальным методам.

Способ 3. Прямое удаление записи в СУБД (SQL)

Когда база данных имеет объем 800 Гб и более, полное тестирование и исправление (ТиИ) может занять несколько суток, что недопустимо. В такой ситуации эффективнее всего прибегнуть к прямому SQL-запросу. Выясним, как найти нужную таблицу.

Для начала воспользуемся функцией ПолучитьСтруктуруХраненияБазыДанных, чтобы узнать имя физической таблицы регистрации изменений для нашего документа:


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

После того как имя таблицы (например, _Document150_ChngRec) и имя поля ссылки (обычно _IDRRef) определены, мы можем выполнить запрос в консоли SQL (Management Studio):

  1. Поиск битой записи: Сначала убедимся, что запись существует.
    
    SELECT * FROM _Document150_ChngRec 
    WHERE _IDRRef = 0x00000000000000000000000000000000
    
  2. Удаление записи: Удаляем только строку с нулевым идентификатором для конкретного узла.
    
    DELETE FROM _Document150_ChngRec 
    WHERE _IDRRef = 0x00000000000000000000000000000000 
    AND _NodeRRef = (SELECT _IDRRef FROM _ExchangePlan45 WHERE _Code = '001')
    

Внимание: любые операции напрямую в SQL нарушают условия лицензионного соглашения и должны проводиться только после создания резервной копии базы данных!

Почему это критично для базы-приемника?

Разберем причину, по которой «фантомный» элемент останавливает весь обмен. В механизме РИБ при загрузке сообщения платформа пытается создать объект или вызвать обработку удаления для каждой записи. Когда она встречает элемент с Zero GUID, срабатывают следующие механизмы:

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

Чтобы избежать подобных «бородавок» в плане обмена в будущем, рекомендуем придерживаться следующих правил:

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

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

← На главную