Как избежать перезаписи данных при совпадении UUID в разных базах 1С при синхронизации через КД 2.0?

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

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

В этой статье мы подробно разберем, почему возникает эта проблема и какие стратегии позволяют гарантированно разделить объекты с одинаковыми идентификаторами, используя механизмы КД 2.0 и Библиотеки стандартных подсистем (БСП).

Почему происходят коллизии GUID и как работает стандартный поиск

Проанализируем ситуацию: в КД 2.0 в правилах конвертации объектов (ПКО) обычно включен флаг «Искать объект по внутреннему идентификатору». Алгоритм работы загрузчика в этом случае следующий:

  1. Проверяется наличие UUID в файле выгрузки.
  2. Выполняется прямой запрос к таблице справочника в базе-приемнике: Справочники.ФизическиеЛица.ПолучитьСсылку(Новый УникальныйИдентификатор(GUIDИзФайла)).
  3. Если ссылка найдена и объект существует, поиск прекращается. Система приступает к обновлению найденного объекта.
  4. Если объект не найден по UUID, выполняются алгоритмы, прописанные в обработчике «Поля поиска».

Основная проблема заключается в том, что поиск по UUID имеет наивысший приоритет и «не знает» о существовании разных узлов обмена. Если в ЗУП №1 и ЗУП №2 созданы разные люди с одинаковым GUID, база-приемник их не отличит.

Решение 1: Использование регистра «Соответствие объектов информационных баз»

Если ваш обмен построен на базе БСП, то самым правильным решением будет использование стандартного регистра сведений СоответствиеОбъектовИнформационныхБаз. Рассмотрим подробнее, почему это работает. Данный регистр хранит связку не просто «GUID — Ссылка», а «УзелОбмена + GUIDИсточник — СсылкаПриемник».

Чтобы задействовать этот механизм и обойти прямое сопоставление по UUID, необходимо выполнить следующие действия:

  1. В правилах конвертации (ПКО) снять флаг «Искать объект по внутреннему идентификатору».
  2. В обработчике «Поля поиска» прописать логику обращения к регистру сведений.

Пример кода для обработчика «Поля поиска»:


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

Запрос.УстановитьПараметр("УзелОбмена", ПараметрыОбъекта["УзелОбмена"]); // Узел должен передаваться в параметрах
Запрос.УстановитьПараметр("ИдентификаторИсточника", Строка(УникальныйИдентификатор));

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    СсылкаНаОбъект = Выборка.СобственнаяСсылка;
    ПрекратитьПоиск = Истина;
КонецЕсли;

Решение 2: Добавление реквизита «Внешний идентификатор»

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

  1. В базе-приемнике добавим в справочник ФизическиеЛица новый реквизит ВнешнийИдентификатор (тип: Строка, длина 36 или больше).
  2. При первой синхронизации заполним этот реквизит строковым представлением GUID из источника.
  3. В настройках ПКО отключим поиск по идентификатору.
  4. В полях поиска установим поиск по реквизиту ВнешнийИдентификатор.

Важный нюанс: Чтобы гарантировать уникальность между разными базами, в ВнешнийИдентификатор лучше записывать связку ПрефиксБазы + "_" + GUID. Рассмотрим пример настройки в обработчике «Перед выгрузкой» в КД 2.0:


// Добавим префикс базы к идентификатору, чтобы исключить коллизии
ИмяУзла = Строка(ОбменДанными.УзелИнформационнойБазы); 
Значение = ИмяУзла + "_" + Строка(Объект.Ссылка.УникальныйИдентификатор());

Теперь, даже если GUID совпадут, строки поиска будут отличаться за счет префикса базы-источника.

Решение 3: Суррогатный ключ (Хеширование полей)

Проанализируем ситуацию, когда невозможно менять структуру базы-приемника. В этом случае мы можем полагаться на комбинацию полей, которая с высокой вероятностью уникальна для человека (СНИЛС, ИНН, ФИО + Дата рождения).

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

  1. Если заполнен СНИЛС — ищем строго по СНИЛС.
  2. Если СНИЛС нет, но есть ИНН — ищем по ИНН.
  3. Если нет уникальных кодов — используем связку ФИО + ДатаРождения + МестоРождения.

Пример реализации в КД 2.0 (событие «Поля поиска»):


Если НомерВариантаПоиска = 1 Тогда
    Если ЗначениеЗаполнено(СвойстваПоиска["СтраховойНомерПФР"]) Тогда
        СтрокаИменСвойствПоиска = "СтраховойНомерПФР";
    Иначе
        // Пропускаем этот вариант, если поле не заполнено
        НомерВариантаПоиска = 2; 
    КонецЕсли;
КонецЕсли;

Если НомерВариантаПоиска = 2 Тогда
    Если ЗначениеЗаполнено(СвойстваПоиска["ИНН"]) Тогда
        СтрокаИменСвойствПоиска = "ИНН";
    Иначе
        НомерВариантаПоиска = 3;
    КонецЕсли;
КонецЕсли;

Если НомерВариантаПоиска = 3 Тогда
    СтрокаИменСвойствПоиска = "Наименование, ДатаРождения";
КонецЕсли;

Профилактика и мониторинг

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

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

Для реализации такой проверки используйте обработчик ПКО «При загрузке»:


Если Не Объект.ЭтоНовый() Тогда
    // Сравним ключевые реквизиты существующего объекта и пришедших данных
    Если Объект.ИНН <> ПараметрыОбъекта["ИНН"] И ЗначениеЗаполнено(Объект.ИНН) Тогда
        ОбщегоНазначения.СообщитьПользователю("Внимание! Обнаружено несовпадение ИНН при совпадении UUID. Возможно дублирование GUID в базах-источниках.");
        // Здесь можно отменить загрузку или пометить объект для проверки
        Отказ = Истина;
    КонецЕсли;
КонецЕсли;

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

← На главную