Как избежать появления дублей номенклатуры в РИБ при загрузке данных из внешних систем?

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

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

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

Причина возникновения проблемы

Когда мы создаем новый элемент справочника Номенклатура методом Справочники.Номенклатура.СоздатьЭлемент(), система генерирует новый случайный GUID. Если два пользователя на узлах "Филиал 1" и "Филиал 2" создадут товар с артикулом "АБ-100", в каждой базе появится объект с собственным уникальным кодом. При обмене с ЦБ оба этих объекта попадут в общую базу. Система 1С не знает, что это один и тот же товар, так как для нее "уникальность" определяется ссылкой, а не строковым артикулом.

Решение 1: Использование детерминированных GUID (Метод хеширования)

Рассмотрим наиболее элегантный способ, который не требует постоянного интернет-соединения в момент записи объекта. Мы можем заставить 1С генерировать не случайный GUID, а GUID, основанный на уникальном ключе из внешней базы (например, на ID товара во внешней системе или на его артикуле).

Алгоритм действий:

  1. Получаем уникальный строковый ключ из внешней базы (например, ExternalID).
  2. Вычисляем хеш-сумму (MD5) от этой строки.
  3. Преобразуем полученный хеш в формат UUID и создаем объект с этим конкретным идентификатором.

Разберем пример кода для реализации этого механизма:


Функция ПолучитьGUIDИзСтроки(Знач ИсходнаяСтрока) Экспорт
    // Используем объект ХешированиеДанных для получения MD5
    Хеш = Новый ХешированиеДанных(АлгоритмХеширования.MD5);
    Хеш.Добавить(ИсходнаяСтрока);
    СтрокаХеша = СтрЗаменить(Строка(Хеш.ХешСумма), " ", "");
    
    // Форматируем строку хеша в формат UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
    // Пример: 4e91244e-1284-4861-a070-58079a49931b
    СтрокаGUID = Сред(СтрокаХеша, 1, 8) + "-" + 
                 Сред(СтрокаХеша, 9, 4) + "-" + 
                 Сред(СтрокаХеша, 13, 4) + "-" + 
                 Сред(СтрокаХеша, 17, 4) + "-" + 
                 Сред(СтрокаХеша, 21, 12);
                 
    Возврат Новый УникальныйИдентификатор(СтрокаGUID);
КонецФункции

// При создании номенклатуры на узле:
НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
УИД_из_внешней_базы = ПолучитьGUIDИзСтроки(ID_Внешней_Системы);
// Устанавливаем ссылку заранее
НоваяСсылка = Справочники.Номенклатура.ПолучитьСсылку(УИД_из_внешней_базы);

// Проверяем, нет ли уже такого объекта (вдруг уже загрузили из ЦБ)
НайденныйОбъект = Справочники.Номенклатура.НайтиПоСсылке(НоваяСсылка);
Если НайденныйОбъект.Пустая() Тогда
    НовыйОбъект.УстановитьСсылкуНового(НоваяСсылка);
    // Заполняем данные...
    НовыйОбъект.Записать();
КонецЕсли;

Преимущество: Даже если 300 узлов одновременно создадут один и тот же товар, у него будет один и тот же GUID. При синхронизации в ЦБ они просто "наложатся" друг на друга, и дублей не возникнет.

Решение 2: Централизация через HTTP-сервис в ЦБ

Проанализируем ситуацию, когда у пользователей есть оперативный доступ к корпоративной сети через VPN или CiscoConnect. В этом случае мы можем организовать "Единую точку ввода" через HTTP-сервис в центральной базе.

Логика работы:

  1. Перед созданием новой номенклатуры на периферийном узле (ПБ) программа отправляет запрос в ЦБ по протоколу HTTP.
  2. В запросе передается уникальный идентификатор из внешней базы (артикул или ID).
  3. Центральная база проверяет у себя наличие этой номенклатуры.
  4. Если номенклатура найдена, ЦБ возвращает её данные и GUID.
  5. Если не найдена, ЦБ сама создает элемент, фиксирует его у себя и возвращает созданные данные в ПБ.
  6. ПБ получает ответ и создает (или обновляет) у себя элемент с тем же GUID, который прислала ЦБ.

Этот метод гарантирует, что ЦБ всегда является "эталоном", а на узлах данные появляются уже синхронизированными. Рассмотрим пример функции запроса к сервису:


Функция ЗапроситьНоменклатуруВЦентре(АртикулВнешний)
    HTTPСоединение = Новый HTTPСоединение("server-cb.company.com", , "user", "pass");
    HTTPЗапрос = Новый HTTPЗапрос("/v1/nomenclature/get_or_create?id=" + АртикулВнешний);
    
    Попытка
        Ответ = HTTPСоединение.Получить(HTTPЗапрос);
        Если Ответ.КодСостояния = 200 Тогда
            ДанныеJSON = Ответ.ПолучитьТелоКакСтроку();
            // Читаем JSON, получаем ГУИД и создаем объект в ПБ (аналогично Решению 1)
            // ...
        КонецЕсли;
    Исключение
        // Обработка ошибки связи: можно либо запретить создание, либо использовать Решение 1
    КонецПопытки;
КонецФункции

Решение 3: Использование внешних источников данных

Поскольку внешняя база доступна через CiscoConnect, мы можем подключить её непосредственно в конфигурацию 1С как ВнешнийИсточникДанных. Это позволит нам работать с таблицами сторонней базы (SQL, Oracle и др.) как с обычными справочниками 1С.

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

Решение 4: Сопоставление данных при загрузке (БСП)

Если изменить процесс создания на узлах невозможно, придется бороться с последствиями при загрузке данных в ЦБ. В Библиотеке стандартных подсистем (БСП) существуют механизмы сопоставления объектов.

Мы можем переопределить обработчик ПриПолученииДанныхОтПодчиненного в плане обмена. Проанализируем алгоритм:

Важное предупреждение: Этот метод довольно сложен в реализации для РИБ, так как требует тонкой настройки регистрации изменений, чтобы "правильная" ссылка улетела обратно на узел и заменила там "неправильную".

Как правильно почистить существующие дубли в РИБ?

Если дубли уже созданы, их необходимо объединить. Однако в РИБ на 300+ узлов стандартная обработка "Поиск и удаление дублей" может вызвать коллапс системы обмена. Разберем почему:

Когда вы объединяете два элемента, 1С помечает один из них на удаление и переписывает ссылки во всех документах, где он участвовал. В РИБ это приводит к тому, что во все 300 узлов полетят сотни измененных документов. Обмен "распухнет", и база может встать.

Рекомендации по замене дублей:

  1. Выполняйте замену порциями (например, по 50-100 элементов в день).
  2. Используйте специализированные скрипты для очистки таблиц регистрации (DataExchangeSelection), чтобы изменения по старым (удаленным) объектам не транслировались на те узлы, где они гарантированно не использовались.
  3. После удаления дублей в ЦБ обязательно дождитесь полной синхронизации всех узлов, прежде чем запускать следующую порцию очистки.

Итоги и рекомендации

Проанализировав все варианты, можно сделать вывод: лучшим решением для РИБ является Решение №1 (Детерминированные GUID). Оно работает автономно, не зависит от качества интернет-соединения в момент ввода данных и гарантирует отсутствие дублей на уровне платформы.

Если же бизнес-процесс требует жесткого контроля параметров (например, цен или остатков из центра), следует комбинировать его с Решением №2 (HTTP-сервисы), используя хеширование как резервный вариант при отсутствии связи.

← На главную