При интеграции 1С:Предприятия с внешними информационными системами (сайтами, CRM, ERP-системами) разработчики часто сталкиваются с необходимостью синхронизации данных. Лучший способ связать объекты в двух разных базах — использовать единый уникальный идентификатор (UUID/GUID). При импорте данных из XML или JSON файлов нам нужно, чтобы создаваемый в 1С элемент справочника получил точно такой же идентификатор, какой у него был во внешней системе.
В рамках этой статьи мы подробно разберем, как программно назначить определенный GUID новому элементу справочника, выясним, почему в отладчике временно может отображаться непонятная строка вида "Объект не найден", и рассмотрим внутренние механизмы хранения ссылок платформой 1С.
В процессе обсуждения на форумах часто возникает ситуация, когда разработчик пытается передать подготовленную ссылку в метод УстановитьСсылкуНового(), но при просмотре значения в отладчике видит странное представление: (177:9009e840f2b901b811e6d50b578c7c46) вместо привычного формата GUID 578c7c46-d50b-11e6-9009-e840f2b901b8. Из-за этого складывается ложное впечатление, что платформа проигнорировала переданное значение и сгенерировала случайный идентификатор. На самом деле это не так.
Давайте разберем по шагам, как правильно написать код для установки идентификатора, а затем детально проанализируем, как СУБД и платформа 1С работают со ссылками на бинарном уровне.
Для того чтобы записать новый элемент справочника с предопределенным идентификатором из файла XML, нам необходимо выполнить следующую последовательность действий:
УникальныйИдентификатор.УстановитьСсылкуНового() к созданному объекту, передав туда подготовленную ссылку.Рассмотрим стандартный программный код, реализующий эту задачу:
// Шаг 1: Получаем строку GUID из внешнего источника
СтрокаGUID = "578c7c46-d50b-11e6-9009-e840f2b901b8";
// Шаг 2: Создаем объект УникальныйИдентификатор
УИД = Новый УникальныйИдентификатор(СтрокаGUID);
// Шаг 3: Получаем ссылку для справочника "Контрагенты" по нашему УИД
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(УИД);
// Шаг 4: Создаем новый элемент справочника в памяти
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
// Шаг 5: Связываем новый объект с подготовленной ссылкой
НовыйКонтрагент.УстановитьСсылкуНового(НоваяСсылка);
// Шаг 6: Заполняем реквизиты и производим запись
НовыйКонтрагент.Наименование = "ООО ""Новые Технологии""";
НовыйКонтрагент.ОбменДанными.Загрузка = Истина; // Рекомендуется при импорте данных
НовыйКонтрагент.Записать();
Этот код абсолютно рабочий. После выполнения метода Записать() в базе данных появится новый контрагент именно с тем GUID, который мы передали в самом начале.
Платформа 1С:Предприятие предоставляет встроенную глобальную функцию XMLЗначение(), которая позволяет выполнить преобразование строки во внутренний тип платформы более компактно. Мы можем существенно сократить наш код, избежав ручного создания объекта УникальныйИдентификатор:
СтрокаGUID = "578c7c46-d50b-11e6-9009-e840f2b901b8";
// Быстрое получение ссылки напрямую из строки GUID
НоваяСсылка = XMLЗначение(Тип("СправочникСсылка.Контрагенты"), СтрокаGUID);
НовыйКонтрагент = Справочники.Contragents.СоздатьЭлемент();
НовыйКонтрагент.УстановитьСсылкуНового(НоваяСсылка);
НовыйКонтрагент.Наименование = "ООО ""Ромашка""";
НовыйКонтрагент.Записать();
Этот вариант работает быстрее и лаконичнее, минимизируя промежуточные преобразования типов в кодовой базе.
Вернемся к главному сомнению разработчиков. Почему при просмотре переменной НоваяСсылка в табло отладчика до момента записи элемента мы видим надпись вида "Объект не найден (177:9009e840f2b901b811e6d50b578c7c46)"?
Во-первых, надпись "Объект не найден" логична. Объект действительно еще не записан в базу данных физически. Ссылка указывает на пустую ячейку памяти СУБД, где в будущем появится наша запись. Платформа честно предупреждает нас об этом.
Во-вторых, формат представления (177:9009e840f2b901b811e6d50b578c7c46) — это внутреннее представление нетипизированной битой ссылки в СУБД. Давайте разберем его структуру:
177 перед двоеточием — это внутренний числовой идентификатор таблицы метаданных (ID типа данных) в структуре вашей конкретной базы данных SQL.9009e840f2b901b811e6d50b578c7c46 — это бинарный массив хранения GUID, в котором байты переставлены местами по алгоритму оптимизации Microsoft SQL Server / PostgreSQL (так называемый byte-swapping).Для ускорения поиска по индексам СУБД переставляет байты GUID версии 1 (которые зависят от времени создания). Давайте применим алгоритм обратной перестановки байтов платформы 1С к строке 9009e840f2b901b811e6d50b578c7c46:
578c7c46) — они становятся первой группой: 578c7c46.d50b) — они становятся второй группой: d50b.11e6) — они становятся третьей группой: 11e6.9009) — они становятся четвертой группой: 9009.e840f2b901b8) — они становятся пятой группой: e840f2b901b8.Объединяем полученные группы через дефис: 578c7c46-d50b-11e6-9009-e840f2b901b8. Как мы видим, это в точности соответствует исходному GUID! Платформа ничего не испортила и не изменила, она просто отобразила внутреннее представление бинарного буфера в СУБД.
Для того чтобы убедиться в правильности установки GUID у еще не записанного объекта в коде, используйте следующий метод:
ИдентификаторНового = НовыйКонтрагент.ПолучитьСсылкуНового().УникальныйИдентификатор();
Сообщить(Строка(ИдентификаторНового)); // Выведет привычный "578c7c46-d50b-11e6-9009-e840f2b901b8"
Для успешного применения данного механизма на практике необходимо придерживаться нескольких важных технических правил:
УстановитьСсылкуНового() работает исключительно тогда, когда метод объекта ЭтоНовый() возвращает Истина. Изменить GUID у уже записанного в базу элемента напрямую невозможно. Если вам нужно сменить GUID существующего элемента, придется создать его копию с новым идентификатором, перенести все реквизиты, переписать все ссылки по базе данных и удалить старый элемент.УстановитьСсылкуНового() доступен только в серверном контексте (или в толстом клиенте). Попытка вызвать его на тонком клиенте приведет к ошибке выполнения "Метод объекта не обнаружен". Всю процедуру создания и назначения ссылок необходимо переносить в серверные модули.ОбменДанными.Загрузка = Истина перед записью объекта. Это отключит лишние проверки бизнес-логики платформы (которые могут перезаписать или сбросить назначенную вами ссылку), а также значительно ускорит процесс импорта данных в базу.Понимание работы УстановитьСсылкуНового() позволяет существенно оптимизировать производительность системы при создании связанных объектов. Рассмотрим классический пример:
Нам необходимо программно создать нового контрагента и сразу же создать его договор (где контрагент является владельцем договора), а затем записать этот договор в реквизит контрагента ОсновнойДоговор.
Без использования метода УстановитьСсылкуНового() нам пришлось бы совершить двойную запись контрагента:
С помощью механизма предварительной генерации ссылок мы можем связать объекты прямо в оперативной памяти и записать каждый из них в базу данных СУБД ровно один раз:
// Генерируем уникальные идентификаторы заранее
УИДКонтрагента = Новый УникальныйИдентификатор();
УИДДоговора = Новый УникальныйИдентификатор();
СсылкаКонтрагента = Справочники.Контрагенты.ПолучитьСсылку(УИДКонтрагента);
СсылкаДоговора = Справочники.ДоговорыКонтрагентов.ПолучитьСсылку(УИДДоговора);
// Создаем договор в памяти и сразу указываем ссылку контрагента-владельца
НовыйДоговор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
НовыйДоговор.УстановитьСсылкуНового(СсылкаДоговора);
НовыйДоговор.Владелец = СсылкаКонтрагента;
НовыйДоговор.Наименование = "Основной договор";
НовыйДоговор.Записать(); // Первая запись в БД (Договор)
// Создаем контрагента в памяти и сразу ссылаемся на еще не записанный в СУБД договор
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКонтрагент.УстановитьСсылкуНового(СсылкаКонтрагента);
НовыйКонтрагент.Наименование = "ООО ""Партнер""";
НовыйКонтрагент.ОсновнойДоговор = СсылкаДоговора;
НовыйКонтрагент.Записать(); // Вторая запись в БД (Контрагент)
Этот подход минимизирует количество транзакций к СУБД, исключает блокировки таблиц и ускоряет работу кода в разы, что критически важно при обработке больших массивов импортируемой информации.