В процессе разработки в среде «1С:Предприятие» перед программистом часто возникает задача интеграции со сторонними информационными системами. Для синхронизации данных обычно используется уникальный идентификатор объекта — GUID (UUID). По умолчанию при выборке ссылочного поля (например, Заказ.Ссылка) платформа возвращает представление ссылки в виде строки вроде «Заказ покупателя 000000034 от 22.10.2018 15:07:25». Однако для внешних баз данных, веб-сервисов или API-интеграций требуется получить именно 36-символьный шестнадцатеричный идентификатор.
Долгое время в платформе 1С существовало жесткое ограничение: получить GUID ссылки непосредственно внутри языка запросов было невозможно. Но платформа развивается, и на сегодняшний день существует несколько проверенных способов решения этой задачи в зависимости от версии вашей платформы и условий выполнения кода. Давайте подробно разберем каждый из них.
Начиная с версии платформы 8.3.22, фирма «1С» добавила долгожданную встроенную функцию в язык запросов и язык выражений СКД — УникальныйИдентификатор() (или УНИКАЛЬНЫЙИДЕНТИФИКАТОР). Это кардинально упростило жизнь разработчикам, так как теперь не нужно прибегать к постобработке или обходным путям.
Проанализируем пример запроса, выполняемого на новой платформе:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Ссылка КАК Ссылка,
| УникальныйИдентификатор(Заказ.Ссылка) КАК ИдентификаторУИД,
| ПРЕДСТАВЛЕНИЕ(УникальныйИдентификатор(Заказ.Ссылка)) КАК ИдентификаторСтрокой
|ИЗ
| Документ.ЗаказПокупателя КАК Заказ";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Выводим результаты в консоль
Сообщить("Ссылка: " + Выборка.Ссылка);
Сообщить("Тип УИД: " + ТипЗнч(Выборка.ИдентификаторУИД)); // Вернет тип "УникальныйИдентификатор"
Сообщить("GUID строкой: " + Выборка.ИдентификаторСтрокой); // Вернет строковое представление GUID
КонецЦикла;
Важные нюансы использования этого способа:
УникальныйИдентификатор() возвращает специальный системный тип данных УникальныйИдентификатор.ПРЕДСТАВЛЕНИЕ(УникальныйИдентификатор(Ссылка)).ПРЕДСТАВЛЕНИЕ, имеет презентационный тип. Это накладывает ограничения на использование полученного поля в самом запросе: вы не сможете использовать его в секции ГДЕ с оператором ПОДОБНО или производить конкатенацию строк на уровне СУБД.Если вы работаете на более ранних версиях платформы (до 8.3.22), получить GUID непосредственно в запросе стандартным путем не получится. В этом случае наиболее производительным и лаконичным решением является постобработка выборки с использованием встроенной функции глобального контекста XMLСтрока().
Рассмотрим по шагам, как это реализовать на практике. Сначала мы пишем самый обычный запрос, выбирающий ссылки на нужные объекты:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Ссылка КАК Ссылка,
| Заказ.Номер КАК Номер
|ИЗ
| Документ.ЗаказПокупателя КАК Заказ";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Преобразуем ссылку в строковый GUID
СтрокаGUID = XMLСтрока(Выборка.Ссылка);
Сообщить("Документ №" + Выборка.Номер + " -> GUID: " + СтрокаGUID);
КонецЦикла;
Почему именно XMLСтрока()?
В платформе 1С есть два основных способа получить строку GUID из ссылки в коде:
Строка(Ссылка.УникальныйИдентификатор()) — этот метод осуществляет обращение к базе данных за объектом (происходит неявное получение объекта/обращение к СУБД), что негативно сказывается на производительности, особенно при обработке больших массивов данных.XMLСтрока(Ссылка) — это чисто математическое и строковое преобразование самой ссылки, которое происходит мгновенно на стороне сервера без единого дополнительного обращения к базе данных. Это самый быстрый и предпочтительный способ получения строкового представления GUID.Вы также можете быстро заполнить колонку в выгруженной Таблице Значений:
ТаблицаРезультатов = Запрос.Выполнить().Выгрузить();
ТаблицаРезультатов.Колонки.Добавить("GUID", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(36)));
Для Каждого СтрокаТЗ Из ТаблицаРезультатов Цикл
СтрокаТЗ.GUID = XMLСтрока(СтрокаТЗ.Ссылка);
КонецЦикла;
Частая ошибка начинающих разработчиков: «замыливание» глаз при чтении GUID
При генерации большого количества документов подряд их уникальные идентификаторы будут создаваться последовательно. Они могут отличаться всего на один символ (обычно в середине строки). Например:
8a342b2e-d696-11e8-8222-000c29cac5e28a342b2f-d696-11e8-8222-000c29cac5e28a342b30-d696-11e8-8222-000c29cac5e2Человеческий мозг устроен так, что при беглом взгляде на эти строки они кажутся абсолютно одинаковыми, так как начало и конец полностью совпадают. Не пугайтесь, если вам покажется, что код выдает дубли — внимательно сверяйте каждый символ идентификатора.
Если ваша задача — вывести уникальный идентификатор в отчете, разработанном на схеме компоновки данных (СКД), то вам также нет необходимости писать дополнительный код постобработки в модулях.
Выясним, как вывести GUID штатными средствами СКД на любых версиях платформы:
ИдентификаторОбъекта.Ссылка.УникальныйИдентификатор().При формировании отчета СКД автоматически перехватит это выражение на уровне платформы и выведет корректный строковый GUID для каждой строки отчета.
Если вам жизненно необходимо выполнять сложные запросы (например, соединения таблиц, фильтрацию с использованием ПОДОБНО, группировку) по текстовому представлению GUID на старых версиях платформы, где встроенная функция УникальныйИдентификатор() недоступна, оптимальным решением станет кэширование. Для решения задачи фильтрации и соединения таблиц без изменения структуры данных подойдёт методика сравнения строки с представлением ссылки в запросе.
Для этого в метаданных нужного объекта (справочника или документа) создают дополнительный реквизит: ИдентификаторСтрокой (Тип: Строка, длина 36 символов). Заполнение этого поля настраивают в модуле объекта в предопределенной процедуре ПередЗаписью:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Если объект новый, у него еще может не быть ссылки.
// В таком случае принудительно получаем ссылку заранее.
Если ЭтоНовый() Тогда
УстановитьСсылкуНового(Документы.ЗаказПокупателя.ПолучитьСсылка());
КонецЕсли;
ИдентификаторСтрокой = XMLСтрока(Ссылка);
КонецПроцедуры
После реализации этого механизма строковый GUID становится полноценным реквизитом базы данных. Вы сможете легко использовать его в любых сложных запросах, индексировать поле для быстрого поиска и передавать в интеграционные решения без дополнительной нагрузки на сервер приложений.
Иногда требуется получить данные напрямую из таблиц СУБД (например, при построении высоконагруженных витрин данных или интеграции через ETL-системы). В СУБД ссылки 1С хранятся в бинарном виде — в полях с типом binary(16) (обычно имена колонок имеют суффикс _IDRRef).
Главная сложность при работе с СУБД напрямую заключается в том, что 1С хранит байты уникального идентификатора в так называемом «перевернутом» виде (это связано с оптимизацией индексов в MS SQL Server). Порядок байтов в UUID на стороне СУБД отличается от стандартного представления RFC 4122, которое мы видим в клиенте 1С.
Для получения привычного нам строкового GUID в MS SQL Server разработчики выполняют побайтовую перегруппировку. Ниже представлен пример SQL-конструкции для преобразования бинарного идентификатора в стандартный текстовый вид:
SELECT
-- Собираем GUID из частей бинарного поля _IDRRef в правильном порядке
SUBSTRING(sys.fn_varbindex_to_hexstr(_IDRRef), 27, 8) + '-' +
SUBSTRING(sys.fn_varbindex_to_hexstr(_IDRRef), 23, 4) + '-' +
SUBSTRING(sys.fn_varbindex_to_hexstr(_IDRRef), 19, 4) + '-' +
SUBSTRING(sys.fn_varbindex_to_hexstr(_IDRRef), 3, 4) + '-' +
SUBSTRING(sys.fn_varbindex_to_hexstr(_IDRRef), 7, 12) AS GUID_Строкой
FROM
_Document34 -- Имя таблицы документа в SQL
В СУБД PostgreSQL для аналогичной перегруппировки байтов применяются функции работы со строками и регулярными выражениями (например, с использованием функций substr и encode).
Подведем итог и определимся с выбором оптимального инструмента:
УникальныйИдентификатор(Ссылка). Это наиболее современный и поддерживаемый стандарт разработки.XMLСтрока(Выборка.Ссылка).Ссылка.УникальныйИдентификатор().