UID объекта в 1С: от просмотра до поиска по идентификатору

· 9 мин

Содержание

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 получить ссылку обратно

Обратная задача встречается чаще прямой: пришёл идентификатор из обмена, из лога, из внешней системы — нужно восстановить по нему ссылку в базе. Делается в два шага.

  1. Создаём значение типа УникальныйИдентификатор из строки:
ИД = Новый УникальныйИдентификатор("8e9b2c1a-0f3d-4a7b-9c2e-5d6f7a8b9c0d");
  1. Получаем ссылку через менеджер нужного объекта методом ПолучитьСсылку():
СсылкаНоменклатуры = Справочники.Номенклатура.ПолучитьСсылку(ИД);
СсылкаДокумента  = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(ИД);

ПолучитьСсылку() не проверяет, существует ли объект в базе. Метод всегда вернёт ссылку указанного типа, даже если объекта с таким 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, а не код.
Можно ли получить UID до записи нового объекта?
Да. У объекта (не ссылки) идентификатор доступен ещё до записи — платформа формирует ссылку заранее. Можно даже задать свой UID новому объекту методом УстановитьНовыйУникальныйИдентификатор() перед записью, если нужно связать его с внешней системой. После записи в базу сменить идентификатор уже нельзя.
Почему UID из навигационной ссылки не совпадает с результатом `Строка(...)`?
В навигационной ссылке ref= идентификатор записан в шестнадцатеричном виде с другим порядком байт и без дефисов. Канонический вид с дефисами даёт только метод Строка(Ссылка.УникальныйИдентификатор()). Это один и тот же идентификатор в разных представлениях.
Как по UID понять, справочник это или документ?
Никак — по одной строке UID тип не определить. Тип вы задаёте сами, выбирая менеджер (Справочники.Номенклатура или Документы.РеализацияТоваровУслуг) при вызове ПолучитьСсылку(). Если тип заранее неизвестен, его нужно передавать вместе с идентификатором.
Вернёт ли `ПолучитьСсылку()` ошибку, если объекта нет?
Нет. Метод всегда отдаёт ссылку указанного типа, даже на несуществующий объект. Существование проверяйте отдельно — запросом по условию Ссылка = &Ссылка или методом ПолучитьОбъект() с проверкой на Неопределено.