При организации обменов данными, сложной выгрузке документов или синхронизации через внешнее соединение COM и веб-сервисы разработчики нередко сталкиваются с ситуацией, когда один документ-источник порождает в базе-приемнике сразу два документа различных типов метаданных. Зачастую для упрощения повторной синхронизации обоим объектам приемника назначают одинаковый УникальныйИдентификатор (GUID), взятый у исходного объекта. Проанализируем, как платформа 1С:Предприятие относится к совпадению идентификаторов у разных типов данных, как это устроено на уровне СУБД и с какими подводными камнями можно столкнуться на практике.
Рассмотрим внутреннюю механику работы ссылочного типа платформы. В системе 1С:Предприятие ссылка не сводится исключительно к шестнадцатибайтному значению GUID. Полноценная ссылка состоит из двух компонентов: типа объекта метаданных и непосредственно уникального идентификатора.
Разберем, как эти данные размещаются в реляционных таблицах базы данных на уровне СУБД (PostgreSQL, MS SQL Server и др.):
_IDRRef выступает первичным ключом только в пределах этой конкретной таблицы. Ограничений уникальности между разными таблицами СУБД не накладывает, поэтому один и тот же бинарный ключ может законно существовать в разных таблицах._TYPE (признак типа), _RTRef (идентификатор метаданных таблицы) и _RRRef (шестнадцатибайтный УИД). Благодаря связке _RTRef и _RRRef ссылки разных видов метаданных с одинаковым GUID никогда не склеиваются и не конфликтуют в запросах.МоментВремени формируется на основе даты документа и его ссылки. Так как ссылка включает в себя идентификатор метаданных, сортировка по моменту времени в запросах и журналах документов работает строго детерминировано и повторяемо.Таким образом, штатные механизмы платформы — Тестирование и исправление (ТИИ), индексация, соединения таблиц в запросах и механизмы ссылочной целостности — продолжают работать полностью штатно.
Несмотря на то что сама платформа 1С корректно изолирует объекты разных таблиц, проблемы могут возникнуть в сопутствующей инфраструктуре, алгоритмах интеграции и пользовательском коде. Выясним, где могут появиться ошибки:
XMLСтрока(Ссылка) возвращает лишь строковый GUID. Если внешняя интеграция использует данную функцию для генерации глобального идентификатора без добавления префикса типа метаданных, уникальность ключа теряется.Рассмотрим подробнее практические подходы к организации создания связанных объектов в базе-приемнике.
Если интеграция работает строго в одну сторону, не взаимодействует с внешними хранилищами без поддержки типизации, а поиск объектов всегда выполняется через менеджер конкретного документа, данный подход допустим. В таком случае в коде поиска всегда явно задается тип метаданных:
// Поиск выполняется строго через менеджер нужного документа
УИД = Новый УникальныйИдентификатор(СтрокаИдентификатора);
СсылкаНаПриход = Документы.ПриходныйКассовыйОрдер.ПолучитьСсылку(УИД);
СсылкаНаРеализацию = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(УИД);
Так как каждый менеджер обращается исключительно к собственной таблице, поиск отработает корректно и без конфликтов.
Если требуется гарантировать уникальность GUID во всей базе и исключить коллизии во внешних системах, сохранив возможность повторной загрузки без ведения регистров, сгенерируем производный идентификатор. Для одного документа оставим оригинальный УИД источника, а для второго создадим новый, вычисленный алгоритмически на основе исходного GUID и имени метаданных.
Применим метод УстановитьСсылкуНового() перед записью создаваемого объекта:
// Создаем производный детерминированный GUID для второго документа
Хеш = Новый ХешированиеДанных(ХешФункция.MD5);
Хеш.Добавить(Строка(УИДИсточника) + "_СписаниеБезналичныхДенежныхСредств");
СтрокаХеша = Хеш.ХешСумма;
// Формируем корректный формат GUID: 8-4-4-4-12 символов
ШаблонGUID = СтрШаблон("%1-%2-%3-%4-%5",
Лев(СтрокаХеша, 8),
Сред(СтрокаХеша, 9, 4),
Сред(СтрокаХеша, 13, 4),
Сред(СтрокаХеша, 17, 4),
Прав(СтрокаХеша, 12)
);
НовыйУИД = Новый УникальныйИдентификатор(ШаблонGUID);
НоваяСсылка = Документы.СписаниеБезналичныхДенежныхСредств.ПолучитьСсылку(НовыйУИД);
ДокументОбъект = Документы.СписаниеБезналичныхДенежныхСредств.СоздатьДокумент();
ДокументОбъект.УстановитьСсылкуНового(НоваяСсылка);
// Заполнение реквизитов документа
ДокументОбъект.Дата = ТекущаяДатаСеанса();
ДокументОбъект.Записать();
Такой подход обеспечивает повторяемость: при повторной выгрузке алгоритм сгенерирует точно такой же идентификатор, что исключит появление дублей и устранит совпадение GUID с другими таблицами.
Разберем наиболее надежный и архитектурно правильный способ, применяемый в Библиотеке стандартных подсистем (БСП). Для связи сущностей «один-ко-многим» каждому объекту в базе-приемнике присваивается собственный случайный GUID, а связь сохраняется в регистре сведений (по аналогии с типовым регистром СоответствияОбъектовИнформационныхБаз).
Схема реализации по шагам:
Такой механизм полностью снимает зависимость между внутренними ключами разных систем и гарантирует масштабируемость интеграции.