Как преобразовать строковые GUID из внешнего источника данных в объекты 1С?

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

При интеграции 1С с внешними системами (будь то сторонние базы данных MS SQL, журналы регистрации в формате SQLite 1Cv8.lgd или внешние API) разработчики часто сталкиваются со специфическим форматом хранения уникальных идентификаторов. Вместо привычного нам 36-символьного представления GUID в СУБД или логах могут записываться строки вида 150:811e005056b8ab6011e9a7953bc1c13f.

В этой статье мы подробно разберем, как расшифровать подобные строки, автоматически определить тип объекта 1С и получить полноценную ссылку без использования медленных и потенциально опасных "грязных хаков" вроде встроенной функции ЗначениеИзСтрокиВнутр().

Понимание структуры данных: почему GUID выглядит именно так?

Давайте проанализируем структуру исходной строки. Запись типа 150:811e005056b8ab6011e9a7953bc1c13f состоит из двух ключевых частей, разделенных двоеточием:

  1. Внутренний код метаданных (префикс "150") — это числовой идентификатор таблицы в конкретной базе данных 1С. Например, справочнику Справочники.Номенклатура на уровне СУБД может соответствовать таблица _Reference150.
  2. Перевернутый GUID (суффикс "811e005056b8ab6011e9a7953bc1c13f") — это 32-символьное шестнадцатеричное представление уникального идентификатора. Платформа 1С хранит GUID в СУБД со смещением байтов (UUID версии 1, оптимизированный под индексацию в Microsoft SQL Server). Чтобы превратить его в стандартный 36-символьный UUID, нам нужно переставить байты в правильном порядке.

Шаг 1. Преобразование "перевернутого" GUID в стандартный формат 1С

Для того чтобы создать объект типа УникальныйИдентификатор, нам необходимо привести 32-символьную последовательность к стандартному виду с дефисами. Разберем по шагам алгоритм восстановления байтового порядка. Нам нужно переставить части строки по определенной схеме.

Ниже представлена готовая функция, которая решает эту задачу с максимальной производительностью с помощью строковых операций платформы:


Функция ВосстановитьGUIDИзСтрокиЖурнала(ЗначениеGUID) Экспорт
    // Пример входа: "811e005056b8ab6011e9a7953bc1c13f"
    // Пример выхода: "3bc1c13f-a795-11e9-811e-005056b8ab60"
    
    Если СтрДлина(ЗначениеGUID) <> 32 Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    СтрокаGUID = Сред(ЗначениеGUID, 25, 8) + "-" + 
                 Сред(ЗначениеGUID, 21, 4) + "-" + 
                 Сред(ЗначениеGUID, 17, 4) + "-" + 
                 Сред(ЗначениеGUID, 1, 4)  + "-" + 
                 Сред(ЗначениеGUID, 5, 12);
                 
    Попытка
        Возврат Новый УникальныйИдентификатор(СтрокаGUID);
    Исключение
        Возврат Неопределено;
    КонецПопытки;
КонецФункции

Шаг 2. Динамическое определение типа объекта по коду СУБД

Чтобы не прописывать соответствие кодов (например, 150) конкретным справочникам или документам вручную (что крайне опасно, так как при обновлении или переносе конфигурации в другую базу эти коды могут измениться), мы воспользуемся платформенным методом ПолучитьСтруктуруХраненияБазыДанных().

Рассмотрим, как один раз при запуске системы сформировать соответствие кодов таблиц СУБД и объектов метаданных 1С, сохранив его в кэш (например, в параметры сеанса или повторно используемый модуль):


Функция ПолучитьТаблицуСоответствияКодовМетаданных() Экспорт
    СоответствиеКодов = Новый Соответствие;
    
    // Получаем структуру хранения для всей конфигурации
    СтруктураБД = ПолучитьСтруктуруХраненияБазыДанных(, Истина);
    
    Для Каждого СтрокаТаблицы Из СтруктураБД Цикл
        ИмяТаблицыХранения = СтрокаТаблицы.ИмяТаблицыХранения; 
        ИмяМетаданных = СтрокаТаблицы.ИмяТаблицы; 
        
        // Анализируем справочники
        Если Найти(ИмяТаблицыХранения, "_Reference") = 1 Тогда
            КодТипа = Число(Сред(ИмяТаблицыХранения, 11)); // Извлекаем числовую часть
            СоответствиеКодов.Вставить(КодТипа, "Справочник." + СтрЗаменить(ИмяМетаданных, "Справочник.", ""));
        
        // Анализируем документы
        ИначеЕсли Найти(ИмяТаблицыХранения, "_Document") = 1 Тогда
            КодТипа = Число(Сред(ИмяТаблицыХранения, 10)); // Извлекаем числовую часть
            СоответствиеКодов.Вставить(КодТипа, "Документ." + СтрЗаменить(ИмяМетаданных, "Документ.", ""));
        КонецЕсли;
    КонецЦикла;
    
    Возврат СоответствиеКодов;
КонецФункции

Шаг 3. Чистое получение ссылки на объект

Теперь мы можем объединить полученные инструменты. Вместо использования тяжелого и нестабильного метода ЗначениеИзСтрокиВнутр(), мы будем работать через менеджеры метаданных. Это гарантирует стабильность кода при любых обновлениях платформы.


Функция ПолучитьСсылкуИзВнешнегоИдентификатора(ВходнаяСтрока, КэшМетаданных) Экспорт
    // ВходнаяСтрока = "150:811e005056b8ab6011e9a7953bc1c13f"
    ПозицияДвоеточия = Найти(ВходнаяСтрока, ":");
    Если ПозицияДвоеточия = 0 Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    КодТипаСтрокой = Лев(ВходнаяСтрока, ПозицияДвоеточия - 1);
    СтрокаGUID = Сред(ВходнаяСтрока, ПозицияДвоеточия + 1);
    
    // Пробуем получить имя метаданных по коду
    КодТипа = Число(КодТипаСтрокой);
    ПолноеИмяМетаданных = КэшМетаданных.Получить(КодТипа);
    
    Если ПолноеИмяМетаданных = Неопределено Тогда
        Возврат Неопределено; // Тип не найден в текущей конфигурации
    КонецЕсли;
    
    // Восстанавливаем UUID
    УИД = ВосстановитьGUIDИзСтрокиЖурнала(СтрокаGUID);
    Если УИД = Неопределено Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    // Получаем менеджер объекта динамически
    МассивПути = СтрРазделить(ПолноеИмяМетаданных, ".");
    ТипОбъекта = МассивПути[0]; // "Справочник" или "Документ"
    ИмяОбъекта = МассивПути[1]; // Например, "Номенклатура"
    
    Если ТипОбъекта = "Справочник" Тогда
        Возврат Справочники[ИмяОбъекта].ПолучитьСсылку(УИД);
    ИначеЕсли ТипОбъекта = "Документ" Тогда
        Возврат Документы[ИмяОбъекта].ПолучитьСсылку(УИД);
    КонецЕсли;
    
    Возврат Неопределено;
КонецФункции

Шаг 4. Оптимизация производительности при выводе списков

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

Вариант А. Создание и использование регистра сопоставления (Рекомендуется)

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

Начиная с версии платформы 8.3.22, в языке запросов 1С появилась штатная функция УникальныйИдентификатор(). Мы можем раз в сутки или по регламентному заданию быстро заполнять этот регистр простым запросом:


ВЫБРАТЬ
    УникальныйИдентификатор(Номенклатура.Ссылка) КАК GUIDСтрока,
    Номенклатура.Ссылка КАК Ссылка
ИЗ
    Справочник.Номенклатура КАК Номенклатура

После заполнения регистра вы можете связать таблицу внешнего источника данных с этим регистром сведений обычным левым соединением (LEFT JOIN) прямо в запросе динамического списка. На выходе вы мгновенно получите готовые ссылки без малейших задержек интерфейса.

Вариант Б. Пакетная обработка в оперативной памяти

Если данные запрашиваются порциями для программной обработки, преобразовывать их нужно пакетами. Давайте разберем алгоритм пакетного сопоставления:

  1. Выгружаем порцию внешних строк во временную таблицу значений.
  2. Быстро обходим ее в цикле, разбирая GUID строковыми функциями и группируя идентификаторы в массивы по типам метаданных.
  3. Для каждого типа метаданных выполняем один запрос к базе данных 1С, передавая массив полученных УникальныйИдентификатор. Это позволяет мгновенно проверить физическое существование объектов в базе 1С и исключить появление "битых" ссылок.

Используя данные методы, мы полностью отказываемся от ненадежных механизмов сериализации внутренних строк 1С, повышаем отказоустойчивость нашей интеграции и сохраняем высокую отзывчивость интерфейса для конечных пользователей.

← На главную