Идентификатор объекта в 1С: GUID, ссылка и УникальныйИдентификатор

· 9 мин

Содержание

Идентификатор объекта в 1С — это его GUID, 36-символьная строка вида e1f2a3b4-1234-5678-9abc-def012345678. Получить его из любой ссылки на справочник, документ или другой объект можно одной строкой: Ид = Ссылка.УникальныйИдентификатор(). Метод возвращает значение типа УникальныйИдентификатор, а в читаемую строку оно переводится через Строка(Ид).

Дальше разберём обратную задачу — получить ссылку по известному GUID, назначить идентификатор новому объекту до записи, выбрать идентификаторы пачкой запросом, сгенерировать случайные GUID для тестов и перевести значение между строкой, объектом и ссылкой. Весь код — на встроенном языке 1С 8.3, платформа «Такси».

Чем ссылка отличается от УникальногоИдентификатора

Это два разных типа, и путаница между ними — источник большинства ошибок.

  • 🔗 Ссылка (СправочникСсылка.Контрагенты, ДокументСсылка.РеализацияТоваровУслуг) — это указатель на объект вместе с его типом. По ссылке можно прочитать реквизиты, получить объект, подставить в реквизит документа.

  • 🆔 УникальныйИдентификатор — только GUID, без типа. Сам по себе он не знает, к какому справочнику относится.

  • 🌐 Навигационная ссылка — ещё одно «имя» объекта, строка e1cib/data/.... Это адрес для гиперссылок внутри интерфейса, в неё GUID входит как часть. Путать её с чистым идентификатором не стоит.

Отсюда главное правило: по одному GUID восстановить ссылку нельзя — нужно ещё знать тип объекта. Поэтому идентификатор почти всегда хранят в паре с именем таблицы (например, Справочник.Контрагенты).

Физически в СУБД GUID лежит в бинарном поле _IDRRef. Напрямую к таблицам базы данных обращаться не нужно и опасно — платформа даёт всё необходимое через встроенный язык. Идентификатор присваивается один раз при создании объекта и после записи не меняется: на нём держатся все ссылки между объектами, движения регистров и записи обменов. Именно поэтому GUID, а не код или наименование, служит ключом сопоставления при переносе данных между базами.

Получаем идентификатор у существующего объекта

Если на руках уже есть ссылка, идентификатор берётся методом УникальныйИдентификатор():

Ид = ВашаСсылка.УникальныйИдентификатор();   // тип УникальныйИдентификатор
СтрокаИд = Строка(Ид);                        // "e1f2a3b4-1234-5678-9abc-def012345678"
Сообщить(СтрокаИд);

Метод работает для любого ссылочного типа: элементов справочников, документов, планов видов характеристик, счетов и так далее. У пустой ссылки (Справочники.Контрагенты.ПустаяСсылка()) идентификатор будет нулевым: 00000000-0000-0000-0000-000000000000.

Из формы объекта ссылку берут из реквизита Объект.Ссылка. На управляемой форме это выглядит так:

&НаКлиенте
Процедура ПоказатьИдентификатор(Команда)
    Сообщить(Строка(Объект.Ссылка.УникальныйИдентификатор()));
КонецПроцедуры

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

Если нужно пройтись по нескольким объектам, ссылку удобно получить из выборки, а GUID вытащить уже в коде:

Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Ид = Выборка.Ссылка.УникальныйИдентификатор();
    // ... дальше работаем с Ид
КонецЦикла;

В интерактивном режиме, без кода, штатной кнопки «показать GUID» нет. Но команда Ещё → Получить ссылку в форме объекта выдаёт навигационную ссылку вида e1cib/data/Справочник.Номенклатура?ref=..., где после ref= стоит тот же идентификатор в сжатом виде.

Назначаем идентификатор новому объекту до записи

Обычно при записи платформа сама присваивает новому объекту случайный GUID. Задавать идентификатор вручную нужно только в особых случаях: когда ссылка требуется до записи (например, два объекта ссылаются друг на друга) или когда идентификатор приходит из внешней системы.

Порядок такой:

  1. Сгенерировать или получить УникальныйИдентификатор.
  2. Построить ссылку через менеджер объекта.
  3. Привязать её к новому объекту методом УстановитьСсылкуНового.
  4. Записать объект.
НовыйИд    = Новый УникальныйИдентификатор();                     // случайный GUID
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(НовыйИд);

Объект = Справочники.Контрагенты.СоздатьЭлемент();
Объект.УстановитьСсылкуНового(НоваяСсылка);
Объект.Наименование = "ООО Ромашка";
Объект.Записать();

УстановитьСсылкуНового сработает только на новом, ещё не записанном объекте. Для уже существующего объекта сменить идентификатор штатно нельзя.

Типичный случай, когда без этого не обойтись, — взаимные ссылки. Например, элемент справочника должен в одном из реквизитов ссылаться сам на себя или на «соседний» объект, который создаётся в той же процедуре. Записать такой объект «вслепую» не выйдет: реквизит требует готовую ссылку, а она появляется только после записи. Выход — заранее получить ссылку через ПолучитьСсылку, проставить её в реквизиты обоих объектов и лишь затем записать их. Без предварительного назначения идентификатора пришлось бы записывать объект дважды: сначала пустым, потом с заполненной ссылкой.

Как получить ссылку обратно по GUID

Обратная операция — построить ссылку из известного идентификатора. Делается методом менеджера ПолучитьСсылку, которому передают объект УникальныйИдентификатор:

Ид     = Новый УникальныйИдентификатор("e1f2a3b4-1234-5678-9abc-def012345678");
Ссылка = Справочники.Контрагенты.ПолучитьСсылку(Ид);

Здесь и всплывает различие из первого раздела: менеджер (Справочники.Контрагенты) задаёт тип, а GUID — конкретный экземпляр. Без правильного менеджера ссылку не собрать.

Важная деталь: ПолучитьСсылку не проверяет, существует ли объект в базе. Он вернёт формально корректную ссылку, даже если такого элемента нет или он помечен и удалён физически. Проверить фактическое наличие можно так:

Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
    Сообщить("Объекта с таким идентификатором в базе нет");
КонецЕсли;

ПолучитьОбъект() возвращает Неопределено, если за ссылкой нет реальной записи, — это надёжнее, чем читать реквизиты вслепую.

А что делать, если тип объекта заранее неизвестен — на руках только строка GUID? Единственный честный способ — перебрать кандидатов. Идентификатор хранят вместе с именем таблицы, и тогда менеджер получают по строке типа:

ПолноеИмя = "Справочник.Контрагенты";          // хранится рядом с GUID
Менеджер  = Тип(ПолноеИмя);                     // для динамики — через метаданные

На практике проще сразу сохранять идентификатор в формате Справочник.Контрагенты:e1f2a3b4-...: по левой части берут менеджер, по правой — GUID. Перебирать все справочники базы в поисках «чьего» это идентификатора — медленно и ненадёжно, так делать не стоит.

Извлечение идентификаторов пачкой через запрос

Частая задача — выгрузить идентификаторы всех объектов выборки (для обмена, сверки, журнала соответствий). В языке запросов 1С нет функции, которая вернула бы GUID прямо в колонку результата. Поэтому схема всегда двухшаговая: запросом получаем ссылки, а идентификаторы снимаем в цикле уже кодом.

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ Ссылка, Наименование
    |ИЗ Справочник.Номенклатура
    |ГДЕ НЕ ПометкаУдаления";

Выборка = Запрос.Выполнить().Выбрать();
Соответствие = Новый Соответствие;        // GUID -> наименование
Пока Выборка.Следующий() Цикл
    Ключ = Строка(Выборка.Ссылка.УникальныйИдентификатор());
    Соответствие.Вставить(Ключ, Выборка.Наименование);
КонецЦикла;

Не пытайтесь читать GUID напрямую из таблиц СУБД (поля _IDRRef, _Reference). Их структура не документирована, зависит от релиза платформы и типа базы, а любое прямое изменение ломает базу. Всё, что нужно, доступно через УникальныйИдентификатор().

Двухшаговая схема не замедляет работу: УникальныйИдентификатор() просто читает уже загруженное значение ссылки, обращения к базе здесь нет. Поэтому цикл по выборке в тысячи строк отрабатывает быстро, а результат сразу складывается в удобную структуру — Соответствие, ТаблицуЗначений или строку обмена.

Для отбора по идентификатору в самом запросе удобнее передать уже готовую ссылку параметром:

Запрос.УстановитьПараметр("Ссылка", ВашаСсылка);
// в тексте запроса: ГДЕ Ссылка = &Ссылка

Генерация случайных идентификаторов для тестов и временных ключей

Отдельный УникальныйИдентификатор можно создать без всякого объекта — конструктором Новый:

Для Счётчик = 1 По 5 Цикл
    Сообщить(Строка(Новый УникальныйИдентификатор()));
КонецЦикла;

Каждый вызов даёт новый случайный GUID. Вероятность совпадения двух таких значений настолько мала, что на практике её не учитывают. Где это пригождается:

  • 🧪 Тесты — подставить заведомо несуществующий идентификатор и проверить реакцию кода.
  • 🔑 Временные ключи — уникальное имя элемента в Соответствии или ТаблицеЗначений, когда осмысленного ключа нет.
  • 🔁 Идемпотентность обменов — пометить сообщение, чтобы не обработать его дважды.
  • 📄 Имена временных файлов — уникальный суффикс, чтобы два процесса не затёрли файл друг друга.

Случайный GUID не возрастает по порядку и не связан со временем создания. Сортировать по нему или выводить из него дату бессмысленно — для этого есть отдельные реквизиты.

Сгенерированный таким образом идентификатор сам по себе ни к чему не привязан: пока вы не передали его в ПолучитьСсылку и не записали объект, это просто уникальное значение. Удобно заранее создать GUID, записать его в журнал обмена или во внешнюю систему, а объект в 1С создать позже — связь между системами сохранится, потому что обе стороны знают один и тот же идентификатор. Это стандартный приём при двусторонних интеграциях, когда порядок создания объектов в разных базах не гарантирован.

Конвертация: строка, УникальныйИдентификатор и ссылка

Три представления одного идентификатора переводятся друг в друга стандартными средствами. Сводка:

Что естьЧто нужноКак получить
строкаУникальныйИдентификаторНовый УникальныйИдентификатор(Стр)
УникальныйИдентификаторстрокаСтрока(Ид) или XMLСтрока(Ид)
строкассылкаМенеджер.ПолучитьСсылку(Новый УникальныйИдентификатор(Стр))
ссылкаУникальныйИдентификаторСсылка.УникальныйИдентификатор()
ссылканавигационная ссылкаПолучитьНавигационнуюСсылку(Ссылка)

Пример полного цикла строка → ссылка → строка:

СтрокаGUID = "e1f2a3b4-1234-5678-9abc-def012345678";

Ид     = Новый УникальныйИдентификатор(СтрокаGUID);
Ссылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(Ид);

Проверка = Строка(Ссылка.УникальныйИдентификатор());   // снова СтрокаGUID

Конструктор Новый УникальныйИдентификатор(Стр) требует ровно 36 символов канонического формата с дефисами. Строка другой длины или с лишними символами вызовет ошибку выполнения. Если источник данных ненадёжный, проверяйте длину или оборачивайте вызов в Попытка … Исключение.

Когда идентификатор приходит из внешнего обмена, строку из ненадёжного источника удобно разбирать через механизм сериализации:

Попытка
    Ид = XMLЗначение(Тип("УникальныйИдентификатор"), СтрокаИзОбмена);
Исключение
    // некорректный формат — логируем и пропускаем
    ЗаписьЖурналаРегистрации("Обмен", УровеньЖурналаРегистрации.Ошибка,
        , , "Неверный GUID: " + СтрокаИзОбмена);
    Возврат;
КонецПопытки;

Пара XMLСтрока / XMLЗначение удобна тем, что это тот же формат, в котором идентификаторы ездят в XML-обменах и планах обмена, — вы работаете с данными ровно так, как их видит платформа.

Не путайте GUID и навигационную ссылку: ПолучитьНавигационнуюСсылку возвращает длинный внутренний адрес e1cib/data/..., пригодный для гиперссылок внутри интерфейса, а не чистый 36-символьный идентификатор.

Проверьте себя
Что вернёт `Справочники.Контрагенты.ПолучитьСсылку(Ид)`, если объекта с таким GUID в базе нет?
Какой тип возвращает метод `Ссылка.УникальныйИдентификатор()`?
Каким методом назначают идентификатор новому объекту до записи?

Частые ошибки при работе с идентификаторами

  • ❌ Хранят GUID без типа. Позже по строке невозможно собрать ссылку — неизвестен менеджер. Сохраняйте идентификатор вместе с именем таблицы.
  • ❌ Считают ссылку от ПолучитьСсылку доказательством, что объект есть. Метод типа не проверяет базу. Нужна проверка через ПолучитьОбъект() = Неопределено.
  • ❌ Сравнивают идентификаторы как строки в разном регистре. Надёжнее сравнивать значения типа УникальныйИдентификатор напрямую (Ид1 = Ид2), а не их строковые представления.
  • ❌ Ждут, что УстановитьСсылкуНового сменит идентификатор существующего объекта. Он работает только до первой записи.
  • ❌ Путают навигационную ссылку с GUID. Строка e1cib/data/... — это адрес, а не идентификатор; передавать её в Новый УникальныйИдентификатор() нельзя.

Частые вопросы

Уникален ли GUID во всей базе или только внутри справочника?
Платформа гарантирует уникальность в пределах таблицы одного типа. Поэтому один и тот же GUID теоретически может встретиться в разных типах объектов, и восстановить ссылку можно только зная менеджер (Справочники.Контрагенты и т. п.).
Сохраняется ли идентификатор при переносе объекта в другую базу?
При обмене и загрузке через XML или планы обмена идентификатор переносится как есть. А вот при ручном вводе такого же объекта в другой базе он получит свой, новый GUID — совпадения наименования недостаточно.
Можно ли задать объекту «красивый» идентификатор вручную?
Технически да — через ПолучитьСсылку с нужным GUID и УстановитьСсылкуНового до записи. Но практического смысла почти нет: идентификатор служебный, пользователь его не видит.
Как получить GUID объекта в режиме «Предприятие» без программирования?
Штатной кнопки именно для GUID нет. Команда Ещё → Получить ссылку даёт навигационную ссылку, где идентификатор зашит после ref=. Чистый GUID проще снять небольшой обработкой с методом УникальныйИдентификатор().
Чем идентификатор отличается от кода и номера?
Код справочника и номер документа — это пользовательские реквизиты, их можно менять и они могут повторяться после перенумерации. GUID задаётся один раз при создании, не меняется и служит для машинной идентификации в обменах и связях.