УникальныйИдентификатор(): работа с GUID ссылок в 1С 8.3
Содержание
Чтобы получить GUID объекта, вызовите у его ссылки метод Ссылка.УникальныйИдентификатор() — он вернёт значение типа УникальныйИдентификатор. Текстовую форму вида 0bf3e4a1-2c5d-11ee-8c3a-00155d010a12 даёт обёртка Строка(...). Обратная задача (есть строка — нужна ссылка) решается связкой Новый УникальныйИдентификатор(строка) и методом менеджера ПолучитьСсылку().
GUID — это внутренний 128-битный идентификатор, который платформа присваивает каждому объекту ссылочного типа (элементу справочника, документу, узлу плана обмена) в момент записи. Он не меняется никогда: ни при переименовании, ни при смене реквизитов, ни при переносе базы. Именно поэтому GUID удобен для внешних систем, обменов и ссылок в веб-сервисах — в отличие от кода или номера, которые можно изменить руками.
Ниже — все рабочие способы получить и преобразовать идентификатор, типовые грабли и ответы на вопросы, которые чаще всего всплывают при обмене данными.
Что такое идентификатор ссылки и чем он не является
Тип значения — УникальныйИдентификатор. Это не строка и не число, а отдельный примитивный тип платформы. Поэтому сравнивать его напрямую со строкой нельзя — сначала приводят к одному типу.
Важно развести два понятия:
- 🔑 Идентификатор ссылки (GUID) — адрес конкретного объекта в базе. Получаем методом
УникальныйИдентификатор(). - 🔗 Навигационная ссылка (
e1cib/...) — это другое. Её формируетПолучитьНавигационнуюСсылку(), и к GUID она отношения не имеет.
У ссылочного типа идентификатор — это метод со скобками, а не свойство. Частая ошибка новичка — написать Ссылка.УникальныйИдентификатор без скобок и получить не значение, а сам метод.
Хранится идентификатор в СУБД как бинарное поле _IDRRef длиной 16 байт. Это пригодится, если вы читаете базу напрямую через SQL (об этом ниже есть важная оговорка про порядок байтов).
Не у всех объектов конфигурации есть GUID. Он существует только у ссылочных типов:
- ✅ есть идентификатор: справочники, документы, планы видов характеристик, планы счетов, планы обмена, бизнес-процессы, задачи, перечисления;
- ❌ нет идентификатора: регистры (сведений, накопления, бухгалтерии), константы, наборы записей.
Запись регистра адресуется не ссылкой, а набором измерений и периодом. Поэтому вопрос «как взять GUID строки регистра сведений» лишён смысла — такого идентификатора у записи регистра просто нет. Если нужна адресация строки регистра во внешней системе, собирайте ключ из значений измерений сами.
Прямой способ через метод ссылки
Это основной и самый быстрый путь. Работает для любого ссылочного значения — справочника, документа, узла плана обмена, счёта плана счетов.
// Есть ссылка на объект
УникИД = Контрагент.УникальныйИдентификатор();
// Если под рукой объект, а не ссылка — сначала берём ссылку
УникИД = ОбъектКонтрагента.Ссылка.УникальныйИдентификатор();
В типе УникальныйИдентификатор нет «пустого» состояния в привычном смысле: у заполненной ссылки идентификатор есть всегда. А вот у пустой ссылки (Справочники.Контрагенты.ПустаяСсылка()) идентификатор состоит из одних нулей: 00000000-0000-0000-0000-000000000000.
Отсюда полезная проверка — не пустая ли ссылка пришла:
Если Не Ссылка.Пустая() Тогда
УникИД = Ссылка.УникальныйИдентификатор();
КонецЕсли;
Для предопределённых элементов идентификатор тоже доступен, но завязываться на него в коде не стоит: при некоторых сценариях обновления конфигурации GUID предопределённого элемента может пересоздаться. Обращайтесь к ним по имени через ПредопределённоеЗначение("Справочник.ВидыНоменклатуры.Услуга") — это надёжнее, чем хранить их GUID.
Как перевести идентификатор в строку и обратно
Для передачи наружу (в файл, в лог, в параметр запроса) GUID почти всегда нужен в виде строки. И наоборот — приняв строку, надо восстановить значение.
Значение → строка:
СтрокаGUID = Строка(УникИД);
// "0bf3e4a1-2c5d-11ee-8c3a-00155d010a12"
Строковая форма — 36 символов: 32 шестнадцатеричные цифры в нижнем регистре и 4 дефиса. Без фигурных скобок, без пробелов.
Строка → значение:
УникИД = Новый УникальныйИдентификатор("0bf3e4a1-2c5d-11ee-8c3a-00155d010a12");
Конструктор принимает строку как с дефисами, так и без них. Если формат битый — платформа выбросит исключение, поэтому входные данные из внешней системы стоит оборачивать в Попытка.
Есть и второй, эквивалентный способ сериализации — через XML-представление. Он удобен, когда вы и так работаете с ЗаписьXML/ЧтениеXML:
Текст = XMLСтрока(УникИД); // в строку
УникИД2 = XMLЗначение(Тип("УникальныйИдентификатор"), Текст); // из строки
Сравнительная таблица, когда что применять:
| Способ | Из чего → во что | Когда удобнее |
|---|---|---|
Строка() / Новый УникальныйИдентификатор() | значение ↔ строка | обычный код, параметры, логи |
XMLСтрока() / XMLЗначение() | значение ↔ строка | внутри XML-сериализации, обмены |
А вот про «конвертацию в число» важно сказать прямо: привести GUID к типу Число нельзя. Идентификатор — это 128 бит, он не помещается в числовой тип платформы и в принципе не задумывался как число. Если во внешней системе идентификатор хранится как большое целое — договаривайтесь о передаче строкой, иначе потеряете точность.
Можно ли достать GUID запросом к базе
Короткий ответ: напрямую в языке запросов функции «дай мне GUID ссылки» нет. В запросе вы получаете саму ссылку, а её идентификатор вычисляете уже в коде:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты
|ГДЕ ИНН = &ИНН";
Запрос.УстановитьПараметр("ИНН", ИНН);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
УникИД = Выборка.Ссылка.УникальныйИдентификатор();
КонецЦикла;
Обратная задача — найти объект по известному GUID — решается без перебора всей таблицы. Не стройте запрос с перебором и сравнением строк: сначала соберите ссылку, потом фильтруйте по ней.
УникИД = Новый УникальныйИдентификатор(ВходящаяСтрока);
Ссылка = Справочники.Контрагенты.ПолучитьСсылку(УникИД);
ПолучитьСсылку() не проверяет, что объект существует. Он просто собирает ссылку из идентификатора. Если объекта с таким GUID в базе нет, вы получите «битую» ссылку, которая выглядит рабочей, но указывает в пустоту.
Проверять существование нужно явно:
Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
Сообщить("Объекта с таким идентификатором в базе нет");
КонецЕсли;
Никогда не считайте, что ссылка из ПолучитьСсылку() ведёт на реальный объект, пока не проверили это явно. Пропуск этой проверки — причина многих ошибок при приёме данных извне.
Если GUID-ов на входе много (например, пакет из внешней системы), не проверяйте каждый по отдельности: ПолучитьОбъект() на каждую ссылку читает объект из базы. Сам ПолучитьСсылку() обращения к СУБД не делает — он лишь собирает ссылку. Поэтому соберите все ссылки в массив, а существование проверьте одним запросом:
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты ГДЕ Ссылка В (&Ссылки)");
Запрос.УстановитьПараметр("Ссылки", МассивСсылок);
НайденныеСсылки = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
В НайденныеСсылки останутся только реально существующие объекты — разом, без цикла с чтением каждого.
Отдельная тема — чтение GUID из СУБД напрямую (SQL-запрос в обход платформы). В поле _IDRRef лежат те же 16 байт, но их половины переставлены относительно строкового представления 1С: платформа при показе меняет местами старшие и младшие 8 байт. Поэтому «склеить» строку GUID из бинарника SQL в лоб не выйдет — нужна перестановка. Прямое чтение таблиц 1С вообще не поддерживается вендором и ломается при обновлениях структуры, так что для продакшена это не метод, а крайний случай для разовой диагностики.
Передача идентификатора в HTTP-сервисах и JSON
При интеграции GUID — естественный ключ, по которому две системы договариваются об одном и том же объекте. Схема всегда одна: наружу отдаём строку, внутрь принимаем строку и восстанавливаем ссылку.
Отдаём объект в ответе HTTP-сервиса:
Ответ = Новый Структура;
Ответ.Вставить("id", Строка(Ссылка.УникальныйИдентификатор()));
Ответ.Вставить("наименование", Ссылка.Наименование);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Ответ);
ТелоОтвета = ЗаписьJSON.Закрыть();
Обратите внимание: идентификатор мы приводим к строке вручную. ЗаписатьJSON не сериализует тип УникальныйИдентификатор сам — если передать его как есть, получите либо ошибку, либо неожиданный формат. Приводите к Строка() заранее.
Принимаем запрос и находим объект:
Данные = ПрочитатьJSON(ЧтениеJSON); // {"id": "0bf3e4a1-..."}
Попытка
УникИД = Новый УникальныйИдентификатор(Данные.id);
Исключение
// некорректный формат идентификатора во входных данных
ВызватьИсключение "Неверный формат id";
КонецПопытки;
Ссылка = Справочники.Контрагенты.ПолучитьСсылку(УникИД);
Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
// отвечаем 404
КонецЕсли;
Два правила, которые экономят время на отладке интеграций:
- 📥 На приёме всегда оборачивайте разбор строки в
Попытка— внешняя система пришлёт мусор рано или поздно. - 📤 На выдаче решите один раз, в каком регистре и с дефисами ли отдаёте GUID, и зафиксируйте это в описании API. Строковая форма 1С — нижний регистр с дефисами.
Один и тот же GUID на всех узлах РИБ
Это ключевая особенность распределённых информационных баз (РИБ), которую важно понимать.
В РИБ идентификатор объекта одинаков на всех узлах. Создали элемент в центральной базе — он приедет в периферийную с тем же самым GUID. Поэтому в РИБ синхронизация идёт именно по ссылкам: платформа узнаёт «тот же самый объект» по совпадению идентификаторов, без поиска по реквизитам.
Из этого следуют практические выводы:
- GUID можно безопасно использовать как сквозной ключ между узлами РИБ — он гарантированно совпадает.
- Ссылку, полученную в одном узле, корректно разобрать в другом через
ПолучитьСсылку().
А вот при обычном обмене (не РИБ: через Конвертацию данных, EnterpriseData, свой формат) всё иначе. Там у каждой базы свои идентификаторы, и один объект в разных базах имеет разные GUID. Сопоставление ведётся по правилам обмена и полям поиска, а соответствие идентификаторов хранит механизм регистрации обмена. Поэтому:
Не передавайте «голый» GUID между базами, которые связаны обычным обменом, а не РИБ. В базе-получателе он будет указывать не на тот объект или в пустоту.
Если нужен единый идентификатор между произвольными базами — заводите собственный реквизит-ключ (например, код из учётной системы) и сопоставляйте по нему.
Типичные ошибки при работе с идентификатором
Самые частые грабли, которые всплывают на код-ревью и в поддержке:
- Метод без скобок.
Ссылка.УникальныйИдентификаторвернёт не значение, а объект-метод. Правильно — со скобками. - Сравнение GUID со строкой напрямую.
Если УникИД = "0bf3..." Тогдавсегда ложно: разные типы. Приводите обе стороны кСтрока()или оба кУникальныйИдентификатор. - Доверие
ПолучитьСсылку()без проверки. Метод не проверяет существование объекта — проверяйте черезПолучитьОбъект() = Неопределено. - Разный регистр и фигурные скобки. Внешние системы иногда шлют GUID в верхнем регистре или в фигурных скобках
{...}. Конструктор 1С скобки не любит — очищайте строку перед разбором. - Ставка на GUID предопределённых элементов. Он может пересоздаться при обновлении — используйте
ПредопределённоеЗначение(). - Попытка «перевести в число». 128 бит в числовой тип не влезут — работайте только со строкой.
Небольшой тест, чтобы проверить, что всё улеглось:
Частые вопросы
Чем GUID отличается от кода или номера объекта?
Как получить GUID по ссылке в консоли запросов?
Ссылка, а идентификатор вычислите в коде обработки результата: Выборка.Ссылка.УникальныйИдентификатор().Почему строка GUID из 1С не совпадает с тем, что я вижу в таблице SQL?
_IDRRef. Чтобы собрать строку из бинарника SQL, половины нужно переставить обратно. Прямое чтение таблиц вендором не поддерживается.Можно ли по GUID узнать, какому типу объекта он принадлежит?
ПолучитьСсылку() вызывается у конкретного менеджера (Справочники.Контрагенты, Документы.РеализацияТоваровУслуг). Тип нужно знать или передавать отдельным полем.GUID объекта меняется при переносе базы или обновлении конфигурации?
.dt, резервном копировании и обновлении. Исключение — GUID предопределённых элементов, на который завязываться не стоит.