Как привести Уникальный идентификатор к строке в запросе 1С и выполнить поиск

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Почему ПРЕДСТАВЛЕНИЕ не работает в условиях запроса

Рассмотрим типичную ошибку начинающих разработчиков. Попытка использовать конструкцию Представление(УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Ссылка)) = "Нужный-GUID" в секции ГДЕ или в поле выбора приводит к ошибке выполнения запроса. Проанализируем причину этого поведения.

Функция ПРЕДСТАВЛЕНИЕ в языке запросов 1С является так называемой "виртуальной" функцией. Она не транслируется напрямую в SQL-запрос. Вместо этого платформа 1С получает данные из базы, и уже на уровне сервера приложений формирует текстовое строковое представление объекта для отображения пользователю. Именно поэтому результат функции ПРЕДСТАВЛЕНИЕ нельзя использовать в логических операциях (сравнениях), группировках или условиях. Система просто не может выполнить это сравнение на стороне СУБД.

Кроме того, важно помнить, что в 1С тип УникальныйИдентификатор не является примитивным типом данных (как строка или число). В базе данных SQL он хранится в бинарном формате binary(16). Прямое приведение бинарных данных к строке через ВЫРАЗИТЬ(... КАК СТРОКА) внутри запроса не поддерживается платформой, так как это была бы крайне ресурсоемкая операция, блокирующая использование индексов.

Способ 1: Использование параметров запроса

Самый простой и правильный способ найти объект по известному строковому GUID — это предварительное преобразование строки в объект типа УникальныйИдентификатор на стороне встроенного языка и передача его в запрос как параметра. Для подготовки таких конструкций удобно использовать продвинутые консоли запросов — для этого есть продвинутая консоль запросов и редактор объектов. Рассмотрим пример кода:


// Строка, полученная из внешней системы
СтрокаGUID = "550e8400-e29b-41d4-a716-446655440000";

// Преобразуем строку в объект типа УникальныйИдентификатор
НужныйУИД = Новый УникальныйИдентификатор(СтрокаGUID);

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Т.Ссылка КАК Ссылка
    |ИЗ
    |   Справочник.Номенклатура КАК Т
    |ГДЕ
    |   УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Т.Ссылка) = &ПараметрУИД";

Запрос.УстановитьПараметр("ПараметрУИД", НужныйУИД);
Результат = Запрос.Выполнить();

В данном случае сравнение происходит на уровне СУБД в бинарном виде, что работает очень быстро. Для тестирования подобных запросов хорошо подходит консоль запросов для управляемых форм.

Способ 2: Метод ПолучитьСсылку()

Если нам заранее известен тип объекта (например, мы точно знаем, что ищем документ определенного вида или элемент конкретного справочника), мы можем вообще обойтись без запроса. Выясним, как использовать метод ПолучитьСсылку(). Этот метод создает объект ссылки на основе GUID, не обращаясь к базе данных в момент создания. Обращение произойдет только тогда, когда вы попытаетесь прочитать данные этого объекта.


СтрокаGUID = "e1c29410-75ad-11e4-80c5-00155d050d03";
УИД = Новый УникальныйИдентификатор(СтрокаGUID);

// Получаем ссылку напрямую через менеджер справочника
СсылкаНаОбъект = Справочники.Контрагенты.ПолучитьСсылку(УИД);

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

Способ 3: Пакетная обработка данных через временные таблицы

Ситуация усложняется, когда внешняя система передает не один идентификатор, а массив из тысяч строк. Выполнять поиск в цикле — плохая практика. В этом случае мы воспользуемся механизмом временных таблиц. Разберем по шагам этот алгоритм:

  1. Создаем таблицу значений с колонкой типа УникальныйИдентификатор.
  2. Заполняем её, преобразуя входные строки в объекты УникальныйИдентификатор.
  3. Передаем таблицу в запрос как параметр.
  4. В запросе помещаем данные во временную таблицу и соединяем с основной таблицей базы данных.

Посмотрим на пример реализации:


// Допустим, МассивСтрокGUID получен извне
ТЗ_Идентификаторы = Новый ТаблицаЗначений;
ТЗ_Идентификаторы.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("УникальныйИдентификатор"));

Для Каждого ТекСтрока Из МассивСтрокGUID Цикл
    НоваяСтрока = ТЗ_Идентификаторы.Добавить();
    НоваяСтрока.Идентификатор = Новый УникальныйИдентификатор(ТекСтрока);
КонецЦикла;

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ВТ_Идентификаторы.Идентификатор КАК ИсхИдентификатор
    |ПОМЕСТИТЬ ВТ_Поиск
    |ИЗ
    |   &ТЗ_Идентификаторы КАК ВТ_Идентификаторы
    |;
    |
    |ВЫБРАТЬ
    |   Документы.Ссылка КАК ДокументСсылка,
    |   ВТ_Поиск.Идентификатор КАК ИсходныйGUID
    |ИЗ
    |   ВТ_Поиск КАК ВТ_Поиск
    |   ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Документы
    |   ПО (УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Документы.Ссылка) = ВТ_Поиск.Идентификатор)";

Запрос.УстановитьПараметр("ТЗ_Идентификаторы", ТЗ_Идентификаторы);
РезультатЗапроса = Запрос.Выполнить();

Способ 4: Индексированный реквизит (для высокой производительности)

Если поиск по строковому GUID является критически важной операцией и выполняется крайне часто на огромных объемах данных, использование функции УНИКАЛЬНЫЙИДЕНТИФИКАТОР() в запросе может замедлить работу. Это происходит из-за того, что СУБД приходится вычислять функцию для каждой строки таблицы (сканирование всей таблицы — Full Scan).

Для оптимизации рекомендуется:

  1. Добавить в объект (справочник или документ) дополнительный реквизит ВнешнийИдентификатор с типом Строка(36).
  2. Установить для этого реквизита свойство Индексировать (или "Индексировать с доп. упорядочиванием").
  3. В процедуре ПередЗаписью программно заполнять этот реквизит значением текущего GUID.

Пример заполнения:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ЭтоНовый() Тогда
        // Записываем строковое представление GUID для быстрого поиска в будущем
        ВнешнийИдентификатор = Строка(Ссылка.УникальныйИдентификатор());
    КонецЕсли;
КонецПроцедуры

Теперь в запросе можно будет выполнять поиск по обычному строковому полю, и этот поиск будет мгновенным благодаря индексу.

Особенности составных типов данных

Проанализируем ситуацию, когда GUID нужно получить от реквизита составного типа (например, ДокументОснование). В запросах функция УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Поле) вернет NULL, если поле не заполнено или содержит значение типа, не имеющего ссылки. Чтобы избежать ошибок, рекомендуется предварительно проверять тип через оператор ССЫЛКА:


ВЫБРАТЬ
    ВЫБОР
        КОГДА Т.ДокументОснование ССЫЛКА Документ.ЗаказПокупателя 
            ТОГДА УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Т.ДокументОснование)
        ИНАЧЕ "Нет ссылки"
    КОНЕЦ КАК ИдентификаторОснования
ИЗ
    Документ.РеализацияТоваровУслуг КАК Т

Рекомендации по интеграции

При передаче данных между 1С и внешними системами через XML или JSON, мы рекомендуем использовать функцию XMLСтрока(Ссылка) — для этих целей удобно использовать универсальный инструмент для обмена и сопоставления данных. Она возвращает строковое представление идентификатора в стандартном формате, который легко преобразуется обратно в тип УникальныйИдентификатор на стороне 1С и корректно воспринимается любыми сторонними языками программирования (Java, Python, C#).

Подведем итог: прямое сравнение результата ПРЕДСТАВЛЕНИЕ со строкой в запросе невозможно из-за архитектуры платформы. Оптимальным решением является использование параметров запроса с типом УникальныйИдентификатор или создание индексированных строковых реквизитов для высоконагруженных систем.

← На главную