Как изменить GUID (уникальный идентификатор) элемента справочника в 1С при обмене данными

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

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

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

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

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

Тем не менее, решить задачу сопоставления объектов с разными GUID технически возможно. Рассмотрим подробнее основные методы.

Метод 1. Настройка правил поиска в «Конвертации данных 2.1» (КД 2)

Если вы используете для обмена обработку «Универсальный обмен данными в формате XML» и правила, созданные в конфигурации «Конвертация данных 2.1», лучшим решением будет тонкая настройка полей поиска. Это позволит избежать изменения GUID в базах, но решит проблему дублирования на лету.

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

Разберем по шагам, как настроить корректное сопоставление:

  1. Откройте правила обмена в конфигурации «Конвертация данных 2.1».
  2. Перейдите в Правила Конвертации Объектов (ПКО) для справочника Контрагенты.
  3. На вкладке «Настройки поиска» убедитесь, что для ключевых свойств (например, ИНН, КПП, Наименование) установлены флаги «Поиск».
  4. Важный шаг: в свойствах самого ПКО обязательно установите флаг «Продолжить поиск по полям поиска, если объект не найден по идентификатору». Это заставит систему сначала попытаться найти контрагента по ИНН/КПП, если по пришедшему GUID поиск не дал результатов.
  5. Для реализации более сложной логики сопоставления используйте обработчик события «Поля поиска» в ПКО. Например, если наименования могут незначительно отличаться, а сопоставлять нужно строго по ИНН и КПП, напишем следующий алгоритм:

// Обработчик "Поля поиска" в ПКО Контрагенты
// Параметры: СвойстваПоиска, Ссылка, Найдено, ПрекратитьПоиск
Если НомерВариантаПоиска = 1 Тогда
    ИНН_Входящий = СвойстваПоиска.Получить("ИНН");
    КПП_Входящий = СвойстваПоиска.Получить("КПП");
    
    Если ЗначениеЗаполнено(ИНН_Входящий) Тогда
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ
            |	Контрагенты.Ссылка КАК Ссылка
            |ИЗ
            |	Справочник.Контрагенты КАК Контрагенты
            |ГДЕ
            |	Контрагенты.ИНН = &ИНН
            |	И (Контрагенты.КПП = &КПП ИЛИ &КПППустой)";
        
        Запрос.УстановитьПараметр("ИНН", ИНН_Входящий);
        Запрос.УстановитьПараметр("КПП", КПП_Входящий);
        Запрос.УстановитьПараметр("КПППустой", Не ЗначениеЗаполнено(КПП_Входящий));
        
        РезультатЗапроса = Запрос.Выполнить();
        Если Не РезультатЗапроса.Пустой() Тогда
            Выборка = РезультатЗапроса.Выбрать();
            Выборка.Следующий();
            // Насильно сопоставляем найденный объект приемника
            Ссылка = Выборка.Ссылка;
            Найдено = Истина;
            ПрекратитьПоиск = Истина;
        КонецЕсли;
    КонецЕсли;
КонецЕсли;

Использование этого метода гарантирует, что при загрузке данных из источника система найдет уже существующего в приемнике контрагента с тем же ИНН/КПП и обновит его реквизиты, не создавая копий с новыми GUID.

Метод 2. Программный обход «Создание – Перенос ссылок – Удаление»

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

Посмотрим на пример реализации такого алгоритма:


Процедура ЗаменитьИдентификаторКонтрагента(СтарыйКонтрагентСсылка, СтрокаНовогоGUID) Экспорт
    
    // Шаг 1. Преобразуем строковое представление GUID в объектный тип
    НовыйGUID = Новый УникальныйИдентификатор(СтрокаНовогоGUID);
    
    // Шаг 2. Генерируем ссылку с нужным нам GUID
    НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(НовыйGUID);
    
    // Проверим, нет ли уже в базе элемента с таким GUID
    Если ЗначениеЗаполнено(НоваяСсылка.ПолучитьОбъект()) Тогда
        ВызватьИсключение "Объект с GUID " + СтрокаНовогоGUID + " уже существует в базе!";
    КонецЕсли;
    
    // Шаг 3. Создаем новый элемент справочника и сопоставляем ему сгенерированную ссылку
    НовыйОбъект = Справочники.Contragents.СоздатьЭлемент();
    НовыйОбъект.УстановитьСсылкуНового(НоваяСсылка);
    
    // Шаг 4. Копируем все реквизиты из старого контрагента
    СтарыйОбъект = СтарыйКонтрагентСсылка.ПолучитьОбъект();
    ЗаполнитьЗначенияСвойств(НовыйОбъект, СтарыйОбъект, , "Ссылка, Предопределенный");
    
    // Копируем табличные части (если они есть)
    Для Каждого ТЧ Из СтарыйОбъект.Метаданные().ТабличныеЧасти Цикл
        ИмяТЧ = ТЧ.Имя;
        НовыйОбъект[ИмяТЧ].Загрузить(СтарыйОбъект[ИмяТЧ].Выгрузить());
    КонецЦикла;
    
    // Записываем новый элемент с требуемым GUID
    НовыйОбъект.Записать();
    
    // Шаг 5. Поиск и замена старых ссылок на новые по всей базе данных
    ТаблицаЗамены = Новый ТаблицаЗначений;
    ТаблицаЗамены.Колонки.Добавить("ИсходноеЗначение");
    ТаблицаЗамены.Колонки.Добавить("НовоеЗначение");
    
    СтрокаЗамены = ТаблицаЗамены.Добавить();
    СтрокаЗамены.ИсходноеЗначение = СтарыйКонтрагентСсылка;
    СтрокаЗамены.НовоеЗначение = НоваяСсылка;
    
    // Используем типовой механизм БСП для безопасной замены ссылок во всех метаданных
    // Это исключит появление "битых" связей в документах и регистрах
    ПараметрыЗамены = ОбщегоНазначенияКлиентСервер.СкопироватьТаблицу(ТаблицаЗамены);
    ПоискИЗаменаЗначений.ЗаменитьСсылки(ПараметрыЗамены);
    
    // Шаг 6. Удаляем старый элемент из информационной базы
    СтарыйОбъект.Удалить();
    
    ЗаписьЖурналаРегистрации("Синхронизация GUID",
        УровеньЖурналаРегистрации.Информация,
        Справочники.Контрагенты,
        НоваяСсылка,
        "Успешно произведена замена GUID для контрагента: " + НовыйОбъект.Наименование);
        
КонецПроцедуры

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

Метод 3. Трюк с XML-сериализацией

Для быстрого исправления единичных объектов без написания масштабного кода замены ссылок можно использовать механизм XML-сериализации платформы 1С. Разберем этот лайфхак по шагам:

  1. Выгрузите нужного контрагента в XML-файл с помощью объекта СериализаторXDTO.
  2. Откройте полученный текстовый файл в любом редакторе (например, Notepad++) и найдите тег с уникальным идентификатором.
  3. Вручную отредактируйте значение GUID на требуемое и сохраните файл.
  4. Удалите старый элемент справочника из базы 1С (помните о необходимости предварительно перенаправить или очистить ссылки на него в документах, иначе вы получите битые ссылки).
  5. Загрузите XML-файл обратно в базу. Платформа создаст точную копию объекта, но уже с новым GUID.

Метод 4. Прямая замена через СУБД (SQL/PostgreSQL) — анализ рисков

Среди разработчиков периодически обсуждается идея прямого изменения GUID через СУБД путем выполнения SQL-запроса к таблице справочника (например, к полю _IDRRef в таблице _ReferenceXX).

Проанализируем этот сценарий. Действительно, технически выполнить запрос класса UPDATE _ReferenceXX SET _IDRRef = &НовыйБинарныйGUID WHERE _IDRRef = &СтарыйБинарныйGUID не составляет труда. Однако делать это категорически запрещено по следующим причинам:

Как восстановить «битые» ссылки по GUID

Если в результате экспериментов вы все-таки удалили объект, не перенаправив ссылки, и в документах отображается надпись <Объект не найден> (84:bf5600145e3710ab11dda4c605dbe824), вы можете восстановить поврежденную ссылочную связь. Для этого достаточно извлечь из текстового представления битой ссылки шестнадцатеричный GUID и программно воссоздать пустой элемент с этим идентификатором.

Посмотрим на пример функции восстановления:


Процедура ВосстановитьБитуюСсылкуКонтрагента(ИмяСправочника, ТекстБитойСсылки)
    
    // Пример текста: "<Объект не найден> (84:bf5600145e3710ab11dda4c605dbe824)"
    ПозицияСкобки = Найти(ТекстБитойСсылки, "(");
    Если ПозицияСкобки = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ОчищеннаяСтрока = Сред(ТекстБитойСсылки, ПозицияСкобки + 1, СтрДлина(ТекстБитойСсылки) - ПозицияСкобки - 1);
    // Преобразуем формат 1С в стандартный вид GUID (добавляем дефисы)
    // Шаблон: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
    Часть1 = Сред(ОчищеннаяСтрока, 25, 8);
    Часть2 = Сред(ОчищеннаяСтрока, 21, 4);
    Часть3 = Сред(ОчищеннаяСтрока, 17, 4);
    Часть4 = Сред(ОчищеннаяСтрока, 1, 4);
    Часть5 = Сред(ОчищеннаяСтрока, 5, 12);
    
    СтандартныйGUIDСтрока = Часть1 + "-" + Часть2 + "-" + Часть3 + "-" + Часть4 + "-" + Часть5;
    
    Попытка
        ЦелевойGUID = Новый УникальныйИдентификатор(СтандартныйGUIDСтрока);
        ВосстановленнаяСсылка = Справочники[ИмяСправочника].ПолучитьСсылку(ЦелевойGUID);
        
        Если Не ЗначениеЗаполнено(ВосстановленнаяСсылка.ПолучитьОбъект()) Тогда
            НовыйЭлемент = Справочники[ИмяСправочника].СоздатьЭлемент();
            НовыйЭлемент.УстановитьСсылкуНового(ВосстановленнаяСсылка);
            НовыйЭлемент.Наименование = "[Восстановлен] " + ТекущаяДата();
            НовыйЭлемент.Записать();
            Сообщить("Успешно восстановлен элемент с GUID: " + СтандартныйGUIDСтрока);
        Иначе
            Сообщить("Элемент с таким GUID уже существует в базе данных!");
        КонецЕсли;
    Исключение
        Сообщить("Не удалось разобрать GUID: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Подведение итогов

Мы детально рассмотрели проблему несовпадения уникальных идентификаторов при одностороннем обмене данными в «1С:Предприятии». Наиболее безопасным и архитектурно верным решением всегда является настройка правил сопоставления в «Конвертации данных». Это исключает необходимость физического изменения данных в базах и предотвращает появление дублей. К радикальным программным методам замены GUID стоит прибегать лишь в крайних случаях, строго соблюдая ссылочную целостность и используя проверенные транзакционные алгоритмы платформы 1С.

← На главную