Как удалить факт удаления объекта из регистрации плана обмена в 1С

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

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

Понимание механизма регистрации удалений

Для начала разберем внутреннюю логику платформы. Когда объект (справочник, документ и т.д.), включенный в состав плана обмена, удаляется из базы, система не может просто забыть о нем. Чтобы передать информацию об удалении в другие узлы, 1С создает запись в специальной служебной таблице. В отличие от обычного изменения, где хранится ссылка на объект, в случае удаления записывается объект типа УдалениеОбъекта. Этот объект содержит только уникальный идентификатор (GUID) того, что раньше было элементом данных.

На уровне СУБД (если используется SQL-вариант) эти данные хранятся в таблицах с префиксами _ReferenceChngRec или _DocumentChngRec. Проанализируем ситуацию: если мы попытаемся прочитать эти записи через стандартный запрос 1С к виртуальной таблице изменений, мы увидим, что поле Ссылка для таких записей будет содержать значение NULL.

Способ 1. Использование консоли запросов

Самый быстрый способ увидеть, какие именно объекты зарегистрированы на удаление, — это использование консоли запросов. Рассмотрим пример для справочника Номенклатура. Нам необходимо обратиться к виртуальной таблице изменений этого справочника.

Выполним следующий запрос:


ВЫБРАТЬ
    Изменения.Ссылка КАК Ссылка,
    Изменения.Узел КАК Узел
ИЗ
    Справочник.Номенклатура.Изменения КАК Изменения
ГДЕ
    Изменения.Ссылка ЕСТЬ NULL
    И Изменения.Узел = &Узел

Разберем, что мы здесь видим. Условие ЕСТЬ NULL позволяет нам отфильтровать только те записи, которые являются «удалениями». Если запрос вернул строки, значит, по указанному узлу обмена зарегистрированы факты удаления объектов. Именно эти записи могут вызывать ошибки типа «задвоение ключевых полей», если в таблице регистрации одновременно существует и живая ссылка, и запись об удалении с тем же идентификатором.

Способ 2. Программное удаление регистрации

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

Проанализируем пример кода для удаления всех регистраций удалений по конкретному узлу:


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

В этом примере мы используем метод ВыбратьИзменения, который позволяет нам итерироваться по зарегистрированным данным. Проверка ТипЗнч(Данные) = Тип("УдалениеОбъекта") является ключевой — она отделяет живые ссылки от информации об удалениях.

Способ 3. Использование типовой обработки БСП

В современных конфигурациях (УТ 11, БП 3.0, ERP и другие), построенных на базе Библиотеки стандартных подсистем (БСП), предусмотрена мощная обработка «Регистрация изменений для обмена данными». Это самый безопасный и наглядный способ для пользователя или администратора.

  1. Откроем обработку через меню «Все функции» (или «Функции для технического специалиста») или через раздел администрирования (Синхронизация данных — Состав отправляемых данных).
  2. Выберем интересующий нас Узел обмена.
  3. В дереве объектов найдем нужный справочник или документ. Если рядом с ним стоит число, значит, есть зарегистрированные изменения.
  4. Нажмем правую кнопку мыши на объекте и выберем пункт «Показать зарегистрированные изменения».
  5. В открывшемся списке записи об удалениях будут помечены специальной иконкой (часто это красный крестик или объект с текстом «Объект удален»).
  6. Выделим нужные строки и нажмем «Удалить регистрацию».

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

Особенности ошибки «Задвоение ключевых полей»

Выясним причину возникновения ошибки, упомянутой в обсуждении. При обмене данными 1С иногда сталкивается с ситуацией, когда в таблице ChngRec (таблица регистрации изменений) нарушается уникальность. Это может произойти из-за сбоев в работе СУБД или при некорректном выполнении транзакций записи изменений.

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

ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Метаданные.Справочники.Номенклатура);

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

Как предотвратить удаление в базе-приемнике?

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

Рассмотрим логику в обработчике «При загрузке»:


Если ТипЗнч(Объект) = Тип("УдалениеОбъекта") Тогда
    // Если мы не хотим, чтобы объект удалялся в этой базе
    Отказ = Истина;
КонецЕсли;

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

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

← На главную