UID объекта в 1С: от просмотра до поиска по идентификатору
Содержание
UID объекта в коде берётся одной строкой: Строка(Ссылка.УникальныйИдентификатор()). Результат — 36-символьная строка вида 8e9b2c1a-0f3d-4a7b-9c2e-5d6f7a8b9c0d. Для справочников, документов, планов видов характеристик и любых ссылочных объектов метод один и тот же.
Если код писать не нужно, идентификатор виден в навигационной ссылке на объект: там он записан в шестнадцатеричном виде. Ниже — оба способа получить UID, обратное преобразование строки в ссылку и подводные камни с предопределёнными элементами.
Что такое UID и почему он один на всю жизнь объекта
UID (он же GUID, UUID) — это 128-битный уникальный идентификатор, который платформа присваивает ссылочному объекту один раз, при первой записи в базу. Больше он не меняется: переименуете номенклатуру, поменяете код контрагента, перепроведёте документ — UID остаётся прежним.
Хранится идентификатор внутри самой ссылки. На уровне СУБД это бинарное поле 16 байт (_IDRRef), на уровне встроенного языка — значение типа УникальныйИдентификатор, спрятанное в объекте Ссылка.
В каноническом виде UID — это 32 шестнадцатеричные цифры, разбитые дефисами на пять групп по схеме 8-4-4-4-12. Именно так его показывает Строка(), так его ждут OData и большинство внешних систем. Регистр букв в группах значения не имеет.
Где UID пригождается на практике:
- 🔗 обмены и интеграции — по UID объект находят в другой базе или во внешней системе;
- 📎 навигационные ссылки
e1cib/data/...— открывают конкретный объект; - 🧩 REST-интерфейс (OData) — в URL объект адресуется именно по идентификатору;
- 🛠 диагностика — по UID из лога или из таблицы СУБД находят «живой» объект в базе.
Важное свойство: UID глобально уникален. Два объекта в одной базе с одинаковым идентификатором встретиться не могут, а совпадение между разными базами практически исключено — идентификатор строится из случайных и машинно-зависимых частей.
Коротко о том, какой способ выбрать под задачу:
| Способ | Что получаем | Когда применять |
|---|---|---|
| Навигационная ссылка | hex-вид UID | Нужно быстро, пользователю, без кода |
Строка(...УникальныйИдентификатор()) | канонический UID с дефисами | Выгрузка, логирование, передача во внешнюю систему |
ПолучитьСсылку() | ссылка из строки UID | Обратная задача — найти объект по идентификатору |
| OData / REST | адресация по UID в URL | Внешняя система читает данные из базы |
UID пустой ссылки — это 00000000-0000-0000-0000-000000000000. Если вы его увидели, значит объект не выбран или ссылка не заполнена.
Как посмотреть идентификатор без программирования
Самый быстрый способ для пользователя — навигационная ссылка на объект. Откройте карточку элемента и получите ссылку стандартной командой платформы (в типовых конфигурациях она называется «Получить ссылку» и доступна из меню Еще в форме объекта или из главного меню).
Платформа выдаст строку вида:
e1cib/data/Справочник.Номенклатура?ref=8e9b2c1a0f3d4a7b9c2e5d6f7a8b9c0d
Значение параметра ref — это и есть UID объекта, только записанный в шестнадцатеричном виде без дефисов.
Внешне hex из навигационной ссылки отличается от канонического UID: в нём другой порядок байт, поэтому «на глаз» привести одно к другому нельзя. Если вам нужен именно канонический вид UID с дефисами — получайте его кодом (см. ниже), а не вручную из навигационной ссылки.
Второй вариант без написания модулей — консоль запросов или обработка «Выполнить код», если они есть в вашей конфигурации или подключены как внешние. Там достаточно выполнить одну строку встроенного языка и увидеть результат. Это уже полупрограммный способ, но писать полноценный модуль не требуется.
Получение UID средствами встроенного языка
Основной метод — УникальныйИдентификатор() у ссылки. Он возвращает значение типа УникальныйИдентификатор, а не строку:
ИД = Номенклатура.Ссылка.УникальныйИдентификатор();
// ИД имеет тип УникальныйИдентификатор
Чтобы получить привычную строку с дефисами, оберните результат в Строка():
СтрокаUID = Строка(Номенклатура.Ссылка.УникальныйИдентификатор());
// "8e9b2c1a-0f3d-4a7b-9c2e-5d6f7a8b9c0d"
Метод работает для любого ссылочного типа: справочники, документы, планы счетов, планы видов характеристик, бизнес-процессы, задачи. Синтаксис везде одинаковый — был бы на руках объект типа «ссылка».
Идентификатор доступен не только у ссылки, но и у объекта — это удобно, когда вы создаёте новый элемент и хотите узнать его UID ещё до записи:
НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
ИД = НовыйТовар.Ссылка.УникальныйИдентификатор(); // уже известен
НовыйТовар.Наименование = "Товар из обмена";
НовыйТовар.Записать();
Если нужно связать объект с внешней системой по заранее известному идентификатору, задайте его до записи методом УстановитьНовыйУникальныйИдентификатор(). А когда требуется просто сгенерировать случайный идентификатор (например, как ключ строки или ссылку на внешний ресурс), создайте пустое значение конструктором:
СлучайныйИД = Новый УникальныйИдентификатор(); // каждый вызов — новый
Если UID нужен для выгрузки в XML или JSON, лучше использовать штатную сериализацию — она даст канонический вид и не зависит от региональных настроек:
СтрокаДляОбмена = XMLСтрока(Ссылка.УникальныйИдентификатор());
Пример, который вытаскивает UID по всем элементам справочника и готов к работе целиком:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
СтрокаUID = Строка(Выборка.Ссылка.УникальныйИдентификатор());
Сообщить(Выборка.Наименование + " — " + СтрокаUID);
КонецЦикла;
Обратите внимание: в выборке мы берём именно поле Ссылка, а уже у него в коде вызываем УникальныйИдентификатор(). Напрямую в тексте запроса UID как отдельное поле получить нельзя — об этом следующий раздел.
Поиск объекта по UID в запросах
В языке запросов нет функции, которая возвращала бы UID отдельным полем или принимала бы строку идентификатора в условии ГДЕ. Запрос оперирует ссылками, а не идентификаторами.
Поэтому поиск «найти объект по известному UID» строят так: строку UID превращают в ссылку средствами встроенного языка, а в запрос передают уже готовую ссылку параметром.
СтрокаUID = "8e9b2c1a-0f3d-4a7b-9c2e-5d6f7a8b9c0d";
ИД = Новый УникальныйИдентификатор(СтрокаUID);
СсылкаНоменклатуры = Справочники.Номенклатура.ПолучитьСсылку(ИД);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНоменклатуры);
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
Сообщить(Результат.Наименование + " / " + Результат.Артикул);
Иначе
Сообщить("Объект с таким идентификатором не найден");
КонецЕсли;
Если же нужно наоборот — получить UID прямо в выборке запроса, — поле Ссылка выбирают в запросе, а УникальныйИдентификатор() вызывают у него уже после выполнения запроса, в цикле обхода выборки (пример в предыдущем разделе).
Как из строки UID получить ссылку обратно
Обратная задача встречается чаще прямой: пришёл идентификатор из обмена, из лога, из внешней системы — нужно восстановить по нему ссылку в базе. Делается в два шага.
- Создаём значение типа
УникальныйИдентификаториз строки:
ИД = Новый УникальныйИдентификатор("8e9b2c1a-0f3d-4a7b-9c2e-5d6f7a8b9c0d");
- Получаем ссылку через менеджер нужного объекта методом
ПолучитьСсылку():
СсылкаНоменклатуры = Справочники.Номенклатура.ПолучитьСсылку(ИД);
СсылкаДокумента = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(ИД);
ПолучитьСсылку() не проверяет, существует ли объект в базе. Метод всегда вернёт ссылку указанного типа, даже если объекта с таким UID нет. Это ссылка «на пустое место».
Поэтому результат почти всегда нужно проверять на существование, прежде чем использовать:
Если ЗначениеЗаполнено(СсылкаНоменклатуры)
И НЕ СсылкаНоменклатуры.ПолучитьОбъект() = Неопределено Тогда
// объект реально есть в базе
КонецЕсли;
Надёжнее проверять запросом: выбрать ссылку по условию Ссылка = &Ссылка и посмотреть, вернулась ли строка. Запрос не поднимает объект целиком в память и работает быстрее, чем ПолучитьОбъект() в цикле по многим идентификаторам.
Если идентификаторов из обмена много, не гоняйте запрос по одному. Соберите ссылки в массив и проверьте существование одним запросом с условием В (&Ссылки):
МассивСсылок = Новый Массив;
Для Каждого СтрокаUID Из МассивСтрокUID Цикл
ИД = Новый УникальныйИдентификатор(СтрокаUID);
МассивСсылок.Добавить(Справочники.Номенклатура.ПолучитьСсылку(ИД));
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ Номенклатура.Ссылка КАК Ссылка
|ИЗ Справочник.Номенклатура КАК Номенклатура
|ГДЕ Номенклатура.Ссылка В (&Ссылки)";
Запрос.УстановитьПараметр("Ссылки", МассивСсылок);
СуществующиеСсылки = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
В СуществующиеСсылки останутся только те объекты, которые реально есть в базе. Остальные идентификаторы из обмена — «битые», их стоит записать в лог или пометить для разбора.
Главный нюанс этого способа: тип объекта нужно знать заранее. По одной строке UID платформа не определит, справочник это или документ — вы сами выбираете менеджер (Справочники.X или Документы.Y), у которого вызываете ПолучитьСсылку(). Если UID приходит из внешней системы, передавайте рядом с ним и имя типа — иначе восстановить ссылку не получится.
Адресация объекта по UID во внешних системах
Когда к базе обращается внешняя система, объект тоже адресуют по идентификатору. Самый частый канал — автоматический REST-интерфейс (OData). В конфигураторе его включают в свойствах конфигурации, затем публикуют базу на веб-сервере.
В OData объект выбирается по UID прямо в адресе запроса:
GET /ваша_база/odata/standard.odata/Catalog_Номенклатура(guid'8e9b2c1a-0f3d-4a7b-9c2e-5d6f7a8b9c0d')
Здесь Catalog_Номенклатура — имя сущности (справочник «Номенклатура»), а внутри guid'...' стоит тот самый канонический UID с дефисами, который возвращает Строка(Ссылка.УникальныйИдентификатор()). То есть для OData идентификатор берётся ровно в том виде, что и для выгрузки, — конвертировать ничего не нужно.
Тот же принцип в обменах через планы обмена и в правилах конвертации данных: объект-источник и объект-приёмник сопоставляются по UID. Поэтому для ссылочных данных идентификатор — самый надёжный ключ сопоставления, в отличие от кода и наименования, которые в двух базах могут различаться.
Исключение из этого правила — предопределённые элементы. Их по UID сопоставлять нельзя, о чём ниже.
UID предопределённых элементов: в чём подвох
Предопределённые элементы (папки, предопределённые значения справочников, счета в типовом плане счетов) ведут себя не так, как обычные. Это самая частая ловушка при работе с идентификаторами.
Ключевой момент: UID предопределённого элемента не гарантированно одинаков в разных базах. Платформа создаёт сам элемент при обновлении конфигурации базы данных, и в этот момент генерирует ему новый идентификатор. В двух базах из одной и той же конфигурации физические UID предопределённых элементов могут отличаться.
Отсюда правило: не адресуйте предопределённые элементы по UID. Для них есть стабильное имя предопределённых данных, которое задаётся в конфигураторе и одинаково во всех базах. Обращайтесь по имени:
// по имени предопределённых данных — надёжно
СсылкаОсновной = Справочники.Склады.Основной;
// через универсальный метод
СсылкаОсновной = ПредопределенноеЗначение("Справочник.Склады.Основной");
// в запросе
// ГДЕ Склады.Ссылка = ЗНАЧЕНИЕ(Справочник.Склады.Основной)
Получить UID у предопределённого элемента можно той же командой Ссылка.УникальныйИдентификатор() — она отработает. Просто не используйте полученное значение как «вечный» ключ для обмена: в другой базе оно может быть другим.
Ещё одна тонкость: до того как конфигурация базы данных обновлена, предопределённый элемент может быть ещё не создан, и ссылка на него окажется незаполненной. Поэтому результат обращения к предопределённому значению в коде тоже имеет смысл проверять через ЗначениеЗаполнено().
Частые вопросы
Чем UID отличается от кода и номера?
Можно ли получить UID до записи нового объекта?
УстановитьНовыйУникальныйИдентификатор() перед записью, если нужно связать его с внешней системой. После записи в базу сменить идентификатор уже нельзя.Почему UID из навигационной ссылки не совпадает с результатом `Строка(...)`?
ref= идентификатор записан в шестнадцатеричном виде с другим порядком байт и без дефисов. Канонический вид с дефисами даёт только метод Строка(Ссылка.УникальныйИдентификатор()). Это один и тот же идентификатор в разных представлениях.Как по UID понять, справочник это или документ?
Справочники.Номенклатура или Документы.РеализацияТоваровУслуг) при вызове ПолучитьСсылку(). Если тип заранее неизвестен, его нужно передавать вместе с идентификатором.Вернёт ли `ПолучитьСсылку()` ошибку, если объекта нет?
Ссылка = &Ссылка или методом ПолучитьОбъект() с проверкой на Неопределено.