При интеграции 1С с внешними системами или переносе данных между базами нередко возникает задача: создать элемент справочника и явно присвоить ему идентификатор, переданный из источника (например, из XML-файла или через COM-соединение). Разберем, как устроена работа со ссылками и идентификаторами в платформе 1С:Предприятие, как правильно сформировать объект типа УникальныйИдентификатор и в каких случаях лучше отказаться от переопределения системного GUID в пользу отдельного реквизита.
Проанализируем природу типа данных УникальныйИдентификатор. В платформе 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 со смещением групп), поэтому для декодирования системных ссылок требуется дополнительная перестановка байтов.
Рассмотрим по шагам процесс создания нового элемента справочника с явным указанием его будущей ссылки:
УникальныйИдентификатор.ПолучитьСсылку() формируем значение ссылки на основе полученного идентификатора.СоздатьЭлемент().УстановитьСсылкуНового(), передав в него ранее сгенерированную ссылку.Записать().Разберем программную реализацию этого процесса:
СтрокаИзXML = "a763cfbbf94f4c678e130e96a3a7f353";
СтрGUID = ПреобразоватьСтрокуВGUID(СтрокаИзXML);
// Формируем уникальный идентификатор и будущую ссылку
УИД = Новый УникальныйИдентификатор(СтрGUID);
НоваяСсылка = Справочники.Номенклатура.ПолучитьСсылку(УИД);
// Проверяем наличие элемента в базе данных
НайденныйОбъект = НоваяСсылка.ПолучитьОбъект();
Если НайденныйОбъект = Неопределено Тогда
// Объект отсутствует, создаем новый
НоменклатураОбъект = Справочники.Номенклатура.СоздатьЭлемент();
// Назначаем подготовленную ссылку до первой записи
НоменклатураОбъект.УстановитьСсылкуНового(НоваяСсылка);
НоменклатураОбъект.Наименование = "Номенклатура из XML";
Попытка
НоменклатураОбъект.Записать();
Сообщить("Успешно создан элемент с кодом: " + НоменклатураОбъект.Код);
Исключение
Сообщить("Ошибка при записи объекта: " + ОписаниеОшибки());
КонецПопытки;
Иначе
// Объект уже существует, выполняем обновление реквизитов при необходимости
НоменклатураОбъект = НайденныйОбъект;
НоменклатураОбъект.Наименование = "Номенклатура из XML (обновлено)";
НоменклатураОбъект.Записать();
КонецЕсли;
При использовании данного механизма необходимо учитывать строгие системные правила платформы:
УстановитьСсылкуНового() работает только для объектов, которые еще ни разу не сохранялись в базе данных (свойство ЭтоНовый() возвращает Истина). Если объект уже записан, изменить его системный уникальный идентификатор штатными методами невозможно.Справочники.<Имя>.ПолучитьСсылку(УИД) не создает запись в базе данных и не блокирует идентификатор. Ссылка физически не существует в таблицах СУБД до вызова Записать().УстановитьСсылкуНового() ссылка обязана соответствовать типу создаваемого объекта. Передача ссылки от другого справочника или документа вызовет системное исключение.Если загрузка данных выполняется не из статического 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);
ЛокальнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(ЛокальныйУИД);
Принудительное назначение системного УникальныйИдентификатор при внешней загрузке не всегда является оптимальным решением. Проанализируем возможные риски и альтернативные варианты организации обмена:
ИдентификаторИсточника (тип Строка, длина 32–36 символов) и установить для него признак «Индексировать». Поиск при синхронизации будет производиться по значению этого реквизита, а внутренние ссылки 1С останутся под управлением платформы.