Как задать уникальный идентификатор для нового элемента справочника при загрузке из XML

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

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

Понятие GUID в 1С и требования к формату строки

Проанализируем природу типа данных УникальныйИдентификатор. В платформе 1С данный тип представляет собой глобальный 128-битный идентификатор (UUID/GUID). Конструктор Новый УникальныйИдентификатор(<Строка>) принимает строку строго определенного стандарта: 36 символов в формате "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" (группы 8-4-4-4-12 шестнадцатеричных символов, разделенные дефисами).

Если из внешнего XML-файла идентификатор выгружен в виде сплошной 32-значной строки без разделителей (например, "a763cfbbf94f4c678e130e96a3a7f353"), передача такого значения напрямую в конструктор вызовет системную ошибку. Прежде чем инициализировать идентификатор, приведем строку к каноническому виду с помощью строковых функций платформы.

Посмотрим на пример функции, преобразующей сплошную строку в канонический GUID:


Функция ПреобразоватьСтрокуВGUID(СплошнаяСтрока)
    
    Если СтрДлина(СплошнаяСтрока) <> 32 Тогда
        ВызватьИсключение "Неверная длина строки идентификатора. Ожидается 32 символа.";
    КонецЕсли;
    
    СтрGUID = Лев(СплошнаяСтрока, 8) + "-" 
            + Сред(СплошнаяСтрока, 9, 4) + "-" 
            + Сред(СплошнаяСтрока, 13, 4) + "-" 
            + Сред(СплошнаяСтрока, 17, 4) + "-" 
            + Прав(СплошнаяСтрока, 12);
            
    Возврат СтрGUID;
    
КонецФункции

Важное замечание: такая простая расстановка дефисов допустима только тогда, когда во внешней системе исходный канонический GUID был просто лишен дефисов. Если же 32-значная строка была получена из внутренних данных СУБД (поле _IDRRef) или из строки битой ссылки вида <Объект не найден> (код_типа:хеш), прямое добавление дефисов не восстановит исходный идентификатор. Внутреннее хранение 1С инвертирует порядок байтов (хранит в формате binary со смещением групп), поэтому для декодирования системных ссылок требуется дополнительная перестановка байтов.

Пошаговый алгоритм: создание объекта с предопределенной ссылкой

Рассмотрим по шагам процесс создания нового элемента справочника с явным указанием его будущей ссылки:

  1. Преобразуем полученную из XML строку в канонический вид и создаем объект УникальныйИдентификатор.
  2. С помощью менеджера справочника и метода ПолучитьСсылку() формируем значение ссылки на основе полученного идентификатора.
  3. Проверяем, существует ли уже объект с такой ссылкой в информационной базе. Это критически важно, так как попытка записать новый объект с уже занятым первичным ключом приведет к ошибке СУБД (нарушение уникальности).
  4. Если объект не найден, создаем новый элемент методом СоздатьЭлемент().
  5. Применяем метод УстановитьСсылкуНового(), передав в него ранее сгенерированную ссылку.
  6. Заполняем реквизиты элемента и выполняем метод Записать().

Разберем программную реализацию этого процесса:


СтрокаИзXML = "a763cfbbf94f4c678e130e96a3a7f353";
СтрGUID = ПреобразоватьСтрокуВGUID(СтрокаИзXML);

// Формируем уникальный идентификатор и будущую ссылку
УИД = Новый УникальныйИдентификатор(СтрGUID);
НоваяСсылка = Справочники.Номенклатура.ПолучитьСсылку(УИД);

// Проверяем наличие элемента в базе данных
НайденныйОбъект = НоваяСсылка.ПолучитьОбъект();

Если НайденныйОбъект = Неопределено Тогда
    // Объект отсутствует, создаем новый
    НоменклатураОбъект = Справочники.Номенклатура.СоздатьЭлемент();
    
    // Назначаем подготовленную ссылку до первой записи
    НоменклатураОбъект.УстановитьСсылкуНового(НоваяСсылка);
    
    НоменклатураОбъект.Наименование = "Номенклатура из XML";
    
    Попытка
        НоменклатураОбъект.Записать();
        Сообщить("Успешно создан элемент с кодом: " + НоменклатураОбъект.Код);
    Исключение
        Сообщить("Ошибка при записи объекта: " + ОписаниеОшибки());
    КонецПопытки;
Иначе
    // Объект уже существует, выполняем обновление реквизитов при необходимости
    НоменклатураОбъект = НайденныйОбъект;
    НоменклатураОбъект.Наименование = "Номенклатура из XML (обновлено)";
    НоменклатураОбъект.Записать();
КонецЕсли;

Ключевые ограничения метода УстановитьСсылкуНового

При использовании данного механизма необходимо учитывать строгие системные правила платформы:

  1. Неизменяемость ссылки после записи. Метод УстановитьСсылкуНового() работает только для объектов, которые еще ни разу не сохранялись в базе данных (свойство ЭтоНовый() возвращает Истина). Если объект уже записан, изменить его системный уникальный идентификатор штатными методами невозможно.
  2. Поведение метода ПолучитьСсылку(). Вызов Справочники.<Имя>.ПолучитьСсылку(УИД) не создает запись в базе данных и не блокирует идентификатор. Ссылка физически не существует в таблицах СУБД до вызова Записать().
  3. Соответствие типов. Передаваемая в УстановитьСсылкуНового() ссылка обязана соответствовать типу создаваемого объекта. Передача ссылки от другого справочника или документа вызовет системное исключение.

Получение GUID через COM-соединение

Если загрузка данных выполняется не из статического XML-файла, а через прямое COM-подключение ко второй информационной базе 1С, возникает сложность с передачей ссылочных типов. Ссылки из другой базы возвращаются на сторону клиента как объекты типа COMОбъект.

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


// Подключение к внешней базе
ПараметрыПодключения = "Srvr=""Server1C"";Ref=""BaseSource"";Usr=""Admin"";Pwd=""123"";";
V83 = Новый COMОбъект("V83.COMConnector");
Соединение = V83.Connect(ПараметрыПодключения);

// Получаем ссылку во внешней базе через запрос или выборку
ВнешняяСсылка = Соединение.Справочники.Номенклатура.НайтиПоКоду("000000123");

// Вызываем метод преобразования в контексте соединения-источника
СтрGUID = Соединение.XMLСтрока(ВнешняяСсылка);

// В текущей базе-приемнике создаем локальный УИД и ссылку
ЛокальныйУИД = Новый УникальныйИдентификатор(СтрGUID);
ЛокальнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(ЛокальныйУИД);

Архитектурные альтернативы: когда не стоит подменять системный GUID

Принудительное назначение системного УникальныйИдентификатор при внешней загрузке не всегда является оптимальным решением. Проанализируем возможные риски и альтернативные варианты организации обмена:

  1. Фрагментация индексов в СУБД. Стандартный генератор платформы 1С создает последовательные идентификаторы на основе текущей временной метки. Это позволяет СУБД (MS SQL Server, PostgreSQL) последовательно добавлять строки в конец страниц индекса. Если вставлять внешние, псевдослучайные GUID, это приводит к постоянному дроблению страниц индексов (Page Splits), деградации производительности записи и разрастанию таблиц.
  2. Выделенный реквизит поиска. Если внешняя система не гарантирует абсолютную неизменность и уникальность идентификаторов, безопаснее добавить в справочник реквизит ИдентификаторИсточника (тип Строка, длина 32–36 символов) и установить для него признак «Индексировать». Поиск при синхронизации будет производиться по значению этого реквизита, а внутренние ссылки 1С останутся под управлением платформы.
  3. Использование регистра соответствий (подход БСП). В типовых конфигурациях 1С, использующих Библиотеку стандартных подсистем, сопоставление выполняется через независимый регистр сведений (например, «Соответствия объектов информационных баз»). В регистре хранятся соответствия между внутренней ссылкой 1С и строковым идентификатором внешней системы. Это полностью изолирует структуру первичных ключей 1С от изменений во внешних системах и исключает конфликты идентификаторов при интеграции с несколькими источниками одновременно.
← На главную