Уникальный идентификатор ссылки 1С: как узнать и применить
Содержание
UUID объекта 1С — это уникальный идентификатор ссылки, который платформа хранит внутри базы. Получить его быстрее всего двумя путями: в коде вызвать у ссылки метод УникальныйИдентификатор(), а в режиме «Предприятие» — скопировать навигационную ссылку на объект, где идентификатор лежит в параметре ref.
Такой идентификатор нужен, когда объект надо однозначно найти без привязки к коду, наименованию или номеру: при обмене данными, в запросах к OData, в интеграциях по HTTP, при разборе логов и отладке. Код и наименование может поменяться, а UUID у записи остаётся неизменным на весь её срок жизни — от создания до удаления.
Всё, что ниже, относится к платформе 1С:Предприятие 8.3 с интерфейсом «Такси» и работает одинаково в любой конфигурации — Бухгалтерии, ЗУП, Управлении торговлей и самописных базах.
Что такое ссылка и зачем у неё внутренний идентификатор
Каждый объект, который хранится в базе как отдельная запись — элемент справочника, документ, запись плана видов характеристик, — адресуется ссылкой (Ссылка). Ссылка не хранит сами данные, она лишь указывает на строку в таблице. Внутри этой ссылки и лежит тот самый UUID — значение типа УникальныйИдентификатор.
Каноническая форма идентификатора — 32 шестнадцатеричные цифры, разбитые на группы 8-4-4-4-12, например 8a1f4e2c-0b7d-11ee-9f3a-00155d01a2b3. Это стандарт UUID, не выдумка 1С.
Важная тонкость: идентификатор уникален в пределах одного типа (одного объекта метаданных). Чтобы по UUID восстановить ссылку, одной строки идентификатора мало — нужно ещё знать, элемент какого справочника или какого документа мы ищем. Поэтому в интеграциях рядом с UUID почти всегда передают и имя типа.
Физически в базе идентификатор лежит бинарным полем из 16 байт (в SQL-хранилище это столбец вида _IDRRef). Каноническая строка 8-4-4-4-12 — это человекочитаемое представление тех же 16 байт, с которым работают встроенный язык, OData и навигационные ссылки.
У пустой ссылки идентификатор нулевой — 00000000-0000-0000-0000-000000000000. По нему удобно отличать «ссылка не заполнена» от «ссылка указывает на удалённый объект».
Как увидеть идентификатор в режиме «Предприятие»
Если идентификатор нужен разово — посмотреть у конкретного элемента, передать коллеге, подставить в адрес — проще всего взять его из навигационной ссылки. Это строка вида:
e1cib/data/Справочник.Номенклатура?ref=8a1f4e2c0b7d11ee9f3a00155d01a2b3
Параметр ref и есть идентификатор объекта в шестнадцатеричном виде. Открыв такую ссылку в том же сеансе, вы попадёте прямо на объект.
Здесь есть одна ловушка, о которой спотыкаются чаще всего. Строка в ref — это те же 16 байт идентификатора, но половины переставлены местами, поэтому собрать из неё каноническую форму 8-4-4-4-12 вручную не получится. Если нужна именно классическая запись UUID, не переставляйте символы на глаз — получите строку кодом (см. раздел про встроенный язык). Для подстановки в ту же навигационную ссылку hex-форма из ref подходит как есть.
Название команды получения ссылки в разных конфигурациях может отличаться, но сам механизм навигационных ссылок есть в платформе всегда.
Ту же навигационную ссылку можно собрать кодом — это удобно, когда нужно разом выгрузить ссылки на пачку объектов или вставить их в письмо:
НавСсылка = ПолучитьНавигационнуюСсылку(Номенклатура.Ссылка);
Сообщить(НавСсылка); // e1cib/data/Справочник.Номенклатура?ref=...
Разберём строку по частям. e1cib/data/ — префикс открытия объекта, Справочник.Номенклатура — полное имя типа, ref= — идентификатор в hex. Если в начале стоит e1cib/list/, ссылка ведёт на список, а не на конкретную запись. Для адресации одного объекта нас интересует именно data.
Как получить UUID в отладчике
Когда объект уже в переменной и вы стоите на точке останова, идентификатор удобно смотреть прямо в отладке Конфигуратора. Два рабочих инструмента:
- Окно Табло — добавьте в него выражение и платформа покажет значение на каждом шаге.
- Команда Вычислить выражение (
Shift+F9) — разовый расчёт в точке останова.
В обоих случаях вводите выражение над вашей ссылкой:
Строка(Объект.Ссылка.УникальныйИдентификатор())
Отладчик вернёт каноническую строку 8-4-4-4-12 — уже без перестановок, в привычном виде. Если смотреть просто Объект.Ссылка.УникальныйИдентификатор(), в Табло отобразится значение типа УникальныйИдентификатор, его строковое представление совпадает с каноническим.
Если переменная и так хранит ссылку (а не объект), обращаться к .Ссылка не нужно — вызывайте метод прямо у неё: Строка(Контрагент.УникальныйИдентификатор()). В 1С:EDT отладка устроена так же — есть окна наблюдения и вычисление выражения, выражение над ссылкой вводится один в один.
Отладка клиент-серверной базы требует, чтобы отладка по протоколу была разрешена в свойствах информационной базы, а у серверного процесса — включён режим отладки. На рабочем сервере это решение администратора: лишние подключения отладчика нагружают процессы.
Как получить UUID в коде встроенного языка
Это основной способ, когда идентификатор нужен программе, а не человеку. У любой ссылки есть метод УникальныйИдентификатор():
Идентификатор = Номенклатура.Ссылка.УникальныйИдентификатор();
ИдентификаторСтрокой = Строка(Идентификатор);
Метод возвращает значение типа УникальныйИдентификатор. В строку его переводят через Строка() или через XMLСтрока() — результат одинаковый, каноническая форма.
Обратно строку превращают в идентификатор конструктором:
Идентификатор = Новый УникальныйИдентификатор("8a1f4e2c-0b7d-11ee-9f3a-00155d01a2b3");
Если конструктору не передавать строку, он сгенерирует новый случайный идентификатор:
НовыйИд = Новый УникальныйИдентификатор(); // каждый вызов даёт другое значение
Это пригодится, когда объекту заранее нужно знать свой будущий идентификатор — например, чтобы отдать его во внешнюю систему до записи. Присвоить готовый идентификатор можно при создании нового объекта методом его менеджера (например, УстановитьНовыйУникальныйИдентификатор у объекта), но менять идентификатор уже записанной строки нельзя — он выдаётся один раз.
В консоли запросов строкового идентификатора напрямую не получить: язык запросов не умеет превращать ссылку в текст UUID. Рабочий приём — выбрать в запросе сами ссылки, а строку собрать уже кодом, обойдя результат:
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Строка(Выборка.Ссылка.УникальныйИдентификатор()));
КонецЦикла;
Чтобы не писать одно и то же под каждый тип, идентификатор любой ссылки удобно брать одной функцией:
Функция ИдентификаторСтрокой(Ссылка) Экспорт
Возврат Строка(Ссылка.УникальныйИдентификатор());
КонецФункции
Метод УникальныйИдентификатор() есть у ссылки любого типа — справочника, документа, задачи, бизнес-процесса, — поэтому такая функция работает со всем сразу.
Как передать UUID во внешнюю систему, OData и HTTP
При интеграции идентификатор почти всегда передаётся строкой в канонической форме. Так его понимают и REST-сервисы, и чужие базы данных.
Стандартный интерфейс OData. Если он опубликован, объект адресуется GUID-ом прямо в URL, а поле идентификатора называется Ref_Key:
http://server/base/odata/standard.odata/Catalog_Номенклатура(guid'8a1f4e2c-0b7d-11ee-9f3a-00155d01a2b3')
Тот же Ref_Key возвращается в JSON-ответе по каждому объекту — это и есть UUID ссылки в канонической записи. По нему же удобно фильтровать выборку: в OData это делается параметром $filter=Ref_Key eq guid'...', а не подстановкой в путь.
Обратная ситуация — внешняя система прислала GUID, а вам нужно записать ссылку в реквизит объекта. Строку приводят к идентификатору, идентификатор — к ссылке, и только потом присваивают реквизиту. Без промежуточного приведения платформа не поймёт, что перед ней именно ссылка нужного типа.
Собственный HTTP-сервис. Идентификатор принимают строкой из параметра запроса и сразу превращают в ссылку:
ИдСтрокой = Запрос.ПараметрыURL["id"];
Идентификатор = Новый УникальныйИдентификатор(ИдСтрокой);
Ссылка = Справочники.Номенклатура.ПолучитьСсылку(Идентификатор);
При приёме строки извне оберните конструктор Новый УникальныйИдентификатор() в попытку: на кривой строке он вызывает исключение. Лучше вернуть внешней системе понятную ошибку, чем аварийно завершить обработку.
Через веб-сервисы (SOAP) и внешние соединения (V83.COMConnector) схема та же: наружу отдаём строку, внутри собираем идентификатор и получаем по нему ссылку.
Обратная задача: получить ссылку по идентификатору
Чаще, чем сам UUID, нужна противоположная операция — по пришедшему идентификатору найти объект. Делает это метод менеджера ПолучитьСсылку():
Идентификатор = Новый УникальныйИдентификатор(ИдСтрокой);
Ссылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(Идентификатор);
Ключевой момент, на котором ошибаются: ПолучитьСсылку() не проверяет, существует ли объект — он просто собирает ссылку из типа и идентификатора. Для несуществующего или удалённого идентификатора вы получите «битую» ссылку, которая выглядит как настоящая.
Чтобы убедиться, что объект реально есть в базе, прочитайте его:
Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
// объекта с таким идентификатором в базе нет
КонецЕсли;
Метод ПолучитьОбъект() вернёт Неопределено, если записи нет. Для массовой проверки лучше один раз выбрать нужные ссылки запросом с условием ГДЕ Ссылка В (&Ссылки), чем читать каждый объект поодиночке.
Когда тип приходит извне строкой, менеджер нужного объекта берут из коллекции по имени — тогда одна функция восстанавливает ссылку для любого справочника:
Функция СсылкаПоИдентификатору(ИмяСправочника, ИдСтрокой) Экспорт
Идентификатор = Новый УникальныйИдентификатор(ИдСтрокой);
Возврат Справочники[ИмяСправочника].ПолучитьСсылку(Идентификатор);
КонецФункции
Для документов так же работает коллекция Документы[ИмяДокумента]. Имя типа при этом — то же, что в навигационной ссылке после e1cib/data/, но без приставки Справочник. или Документ..
Сравнивать идентификаторы между собой можно напрямую: равенство ссылок (Ссылка1 = Ссылка2) и равенство самих идентификаторов (Ид1 = Ид2) платформа понимает без приведения к строке. Переводить в текст только ради сравнения не нужно — это лишняя операция и риск сравнить разные формы записи.
Где встречается «сырой» идентификатор при разборе проблем
Идентификатор попадается не только там, где вы его запрашиваете. Он всплывает, когда нужно разобраться, какая именно запись вызвала сбой:
- 📄 В технологическом журнале и в текстах системных сообщений объект нередко показан ссылкой с идентификатором внутри. По нему находят конкретную проблемную запись, даже если её наименование в сообщение не попало.
- 🧾 В выгрузках XML (сериализация объектов, обмен данными) ссылка пишется вместе с идентификатором — так принимающая база связывает запись со своей.
- 🗂️ В журнале регистрации запись событий привязана к ссылке на объект; открыв событие, вы перейдёте на сам объект.
Алгоритм разбора простой: взяли идентификатор из лога или выгрузки, определили тип объекта по контексту, собрали ссылку функцией СсылкаПоИдентификатору() из раздела выше и открыли её — либо проверили, что объекта уже нет. Это быстрее, чем искать запись перебором по наименованию, особенно когда наименований-дублей много.
Особенности хранения и частые ошибки
Несколько моментов, из-за которых идентификатор «не находится» или ведёт себя не так, как ждали.
- 🔁 Перестановка байтов в
ref. Hex из навигационной ссылки и каноническая строка изСтрока()описывают один идентификатор, но порядок символов разный. Сравнивать их напрямую нельзя — приведите оба к одному виду кодом. - 🧩 UUID без типа бесполезен. Одна строка идентификатора не говорит, в каком справочнике искать. Храните и передавайте имя типа рядом с UUID, иначе
ПолучитьСсылку()будет не у какого менеджера вызвать. - 🗑️ Удалённый объект оставляет «живую» ссылку. После удаления или пометки на удаление
ПолучитьСсылку()по старому идентификатору по-прежнему вернёт ссылку. Проверяйте существование через чтение объекта или запрос. - 🔀 Копирование и загрузка данных. При выгрузке/загрузке через XML или при копировании элемента платформа сохраняет исходный идентификатор, а вот при ручном создании нового элемента он будет другим. Не считайте, что «такой же товар» в двух базах имеет один UUID.
- 📅 Идентификатор не меняется. Переименование, смена кода, перепроведение документа на UUID не влияют — это и есть причина брать именно его для надёжной привязки записей между базами и системами.
Чем UUID отличается от кода элемента или номера документа?
Можно ли задать объекту свой идентификатор?
Новый УникальныйИдентификатор() и установку идентификатора до записи. У уже существующей записи идентификатор поменять нельзя.Почему строка из `ref` не совпадает с канонической формой?
ref хранятся те же 16 байт, но две половины переставлены местами. Получите каноническую строку кодом через Строка() — и она совпадёт с тем, что показывает отладчик и OData.Как по UUID понять, что объект удалён?
ПолучитьСсылку() вернёт ссылку всегда. Прочитайте объект: если Ссылка.ПолучитьОбъект() вернул Неопределено, записи в базе нет.