Как правильно собрать строку из GUID элементов справочника и сохранить ее в константе 1С?

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

Приветствуем вас, коллеги-разработчики 1С! Сегодня мы с вами разберем очень практичную и часто встречающуюся задачу: как эффективно собрать список уникальных идентификаторов (GUID) элементов справочника, объединить их в строку с заданным разделителем и сохранить эту строку в константе с типом ХранилищеЗначения. Мы проанализируем различные подходы, начиная от простых циклов и заканчивая оптимизированными запросами, а также рассмотрим альтернативные способы хранения данных.

Представим, что у нас есть конфигурация с существующим справочником «Платформы», который содержит реквизиты: Наименование, ЧисловойКод и Ключевая (булево). Также в конфигурации присутствует константа «ПлатформыРезерв» с типом данных ХранилищеЗначения. Наша цель — поместить в эту константу строку, состоящую из GUID всех или некоторых элементов справочника «Платформы», разделенных символом точка с запятой (;).

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

Решение 1: Формирование строки GUID через Массив и функцию СтрСоединить

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

Разберем по шагам, как это реализовать:

  1. Создаем новый объект Массив, который будет хранить наши GUIDы.
  2. Получаем выборку всех элементов справочника «Платформы».
  3. В цикле обхода выборки для каждого элемента получаем его уникальный идентификатор с помощью метода Ссылка.УникальныйИдентификатор() и добавляем его в наш массив.
  4. После завершения цикла используем функцию СтрСоединить(), чтобы объединить все элементы массива в одну строку, используя в качестве разделителя точку с запятой (;).
  5. Полученную строку сохраняем в константу «ПлатформыРезерв».

Посмотрим на пример кода для этого подхода:


// Создаем новый массив для хранения GUID
МассивГУИД = Новый Массив;

// Получаем ссылку на справочник "Платформы"
СправочникПлатформы = Справочники.Платформы;

// Выполняем выборку всех элементов справочника
Выборка = СправочникПлатформы.Выбрать();

// Обходим выборку и добавляем GUIDы в массив
Пока Выборка.Следующий() Цикл
    МассивГУИД.Добавить(Выборка.Ссылка.УникальныйИдентификатор());
КонецЦикла;

// Объединяем элементы массива в строку, используя ";" как разделитель
СтрокаГУИД = СтрСоединить(МассивГУИД, ";");

// Сохраняем полученную строку в константу "ПлатформыРезерв"
Константы.ПлатформыРезерв.Установить(СтрокаГУИД);

Этот способ прост и понятен, но для справочников с очень большим количеством элементов он может быть не самым производительным, поскольку мы выполняем итерацию по каждому элементу на стороне 1С-клиента или сервера приложений.

Решение 2: Оптимизация получения GUID с помощью Запроса

Когда речь идет о работе с большими объемами данных, всегда стоит рассмотреть использование запросов к базе данных. Запросы выполняются на стороне СУБД, что значительно быстрее, чем итерации в цикле на стороне 1С. Мы можем поручить СУБД собрать все необходимые GUIDы и вернуть нам их уже в виде удобного объекта.

Проанализируем ситуацию: нам нужны только уникальные идентификаторы ссылок. Запрос идеально подходит для этой цели. Мы можем использовать функцию УНИКАЛЬНЫЙИДЕНТИФИКАТОР() непосредственно в тексте запроса.

Посмотрим на пример кода, который использует объект Запрос:


// Создаем новый объект Запрос
Запрос = Новый Запрос;

// Формируем текст запроса: выбираем уникальные идентификаторы ссылок
Запрос.Текст = 
    "ВЫБРАТЬ
    |    УНИКАЛЬНЫЙИДЕНТИФИКАТОР(СправочникПлатформы.Ссылка) КАК GUID
    |ИЗ
    |    Справочник.Платформы КАК СправочникПлатформы";

// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();

// Выгружаем колонку "GUID" в массив
МассивГУИД = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("GUID");

// Объединяем элементы массива в строку
СтрокаГУИД = СтрСоединить(МассивГУИД, ";");

// Сохраняем полученную строку в константу
Константы.ПлатформыРезерв.Установить(СтрокаГУИД);

Этот подход значительно более эффективен, особенно для больших справочников. Мы минимизируем количество операций на стороне 1С, перекладывая основную нагрузку на СУБД.

Дополнительно, если нам нужно собрать GUIDы только тех платформ, у которых установлен реквизит Ключевая в значение Истина, мы можем легко модифицировать запрос, добавив условие ГДЕ:


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

РезультатЗапроса = Запрос.Выполнить();
МассивГУИД = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("GUID");
СтрокаГУИД = СтрСоединить(МассивГУИД, ";");
Константы.ПлатформыРезерв.Установить(СтрокаГУИД);

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

Решение 3: Прямое хранение Массива или СпискаЗначений в ХранилищеЗначения

Теперь рассмотрим подход, который не был явно предложен в исходной теме, но является очень мощным и гибким благодаря возможностям типа ХранилищеЗначения. Вместо того чтобы преобразовывать массив GUID в строку с разделителем, мы можем напрямую сохранить объект Массив или СписокЗначений, содержащий объекты типа УникальныйИдентификатор, в константе ХранилищеЗначения.

Почему этот подход может быть лучше? Давайте рассмотрим подробнее:

  1. Упрощение кода: Нам не потребуется явная операция СтрСоединить() при записи и СтрРазделить() (или другой парсинг) при чтении. ХранилищеЗначения само сериализует и десериализует объект.
  2. Сохранение типа данных: Мы храним непосредственно объекты УникальныйИдентификатор, а не их строковое представление. Это позволяет напрямую использовать их, например, для получения ссылки на объект: Справочники.Платформы.ПолучитьСсылку(ГУИД).
  3. Надежность: Менее подвержено ошибкам, если в будущем изменится формат GUID или потребуется использовать другой разделитель.
  4. Гибкость: Если потребуется добавить к GUIDам какую-либо дополнительную информацию, можно будет использовать СписокЗначений, где в качестве значений будут храниться УникальныйИдентификатор, а в качестве представлений —, например, наименования.

Недостатки такого подхода:

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

Посмотрим на пример кода для прямого сохранения Массива:


// Создаем новый объект Запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    СправочникПлатформы.Ссылка.УникальныйИдентификатор КАК GUID
    |ИЗ
    |    Справочник.Платформы КАК СправочникПлатформы";

// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();

// Выгружаем колонку "GUID" в массив.
// Важно: здесь мы получаем объекты УникальныйИдентификатор, а не строки!
МассивГУИД = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("GUID");

// Сохраняем весь массив в константу "ПлатформыРезерв"
// ХранилищеЗначения автоматически сериализует массив
Константы.ПлатформыРезерв.Установить(МассивГУИД);

Для чтения данных из константы и использования их, код будет выглядеть так:


// Получаем хранимый объект из константы
// ХранилищеЗначения автоматически десериализует объект в исходный тип (Массив)
МассивГУИДИзКонстанты = Константы.ПлатформыРезерв.Получить();

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

Если мы хотим использовать СписокЗначений, процесс аналогичен:


// Создаем новый объект Запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    СправочникПлатформы.Ссылка.УникальныйИдентификатор КАК GUID,
    |    СправочникПлатформы.Наименование КАК Наименование
    |ИЗ
    |    Справочник.Платформы КАК СправочникПлатформы";

РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

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

Константы.ПлатформыРезерв.Установить(СписокПлатформ);

И чтение:


СписокПлатформИзКонстанты = Константы.ПлатформыРезерв.Получить();

Если ТипЗнч(СписокПлатформИзКонстанты) = Тип("СписокЗначений") Тогда
    Для Каждого ЭлементСписка Из СписокПлатформИзКонстанты Цикл
        Сообщить("Платформа: " + ЭлементСписка.Представление + ", GUID: " + ЭлементСписка.Значение);
    КонецЦикла;
КонецЕсли;

Этот подход предпочтителен, если нет строгих требований к хранению GUID именно в виде строки с разделителями, так как он более гибок и менее подвержен ошибкам.

Решение 4: Использование ТаблицыЗначений для более сложной структуры данных

Если в будущем потребуется хранить не только GUID, но и другую информацию о платформах (например, значение реквизита "Ключевая", "Наименование", или "ЧисловойКод"), то ТаблицаЗначений будет наиболее структурированным и удобным способом. Мы можем создать ТаблицаЗначений с нужными колонками, заполнить ее и сохранить целиком в ХранилищеЗначения.

Рассмотрим пример, как это сделать:


// Создаем новый объект Запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    СправочникПлатформы.Ссылка.УникальныйИдентификатор КАК GUID,
    |    СправочникПлатформы.Наименование КАК Наименование,
    |    СправочникПлатформы.Ключевая КАК Ключевая
    |ИЗ
    |    Справочник.Платформы КАК СправочникПлатформы";

// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();

// Выгружаем результат запроса в ТаблицуЗначений
ТаблицаПлатформ = РезультатЗапроса.Выгрузить();

// Сохраняем ТаблицуЗначений в константу "ПлатформыРезерв"
Константы.ПлатформыРезерв.Установить(ТаблицаПлатформ);

Для чтения и использования данных из ТаблицыЗначений:


// Получаем ТаблицуЗначений из константы
ТаблицаПлатформИзКонстанты = Константы.ПлатформыРезерв.Получить();

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

Данный подход является наиболее масштабируемым и удобным для хранения разнородных данных о списках объектов.

Общие рекомендации и важные моменты при работе с ХранилищемЗначения

Давайте проанализируем некоторые важные аспекты, касающиеся использования ХранилищаЗначения и оптимизации:

  1. Особенности ХранилищаЗначения:
    • ХранилищеЗначения предназначено для хранения значений различных типов в сериализованном (бинарном) виде, часто со сжатием данных. Это позволяет экономить место для больших объектов.
    • Данные, хранящиеся в полях типа ХранилищеЗначения, не поддерживают индексирование. По таким полям нельзя напрямую упорядочивать данные в запросах, выполнять поиск или фильтрацию. Если вам потребуется часто искать или фильтровать элементы по GUIDам, хранящимся в константе, то каждый раз придется извлекать весь список из ХранилищаЗначения и обрабатывать его в коде, что может быть неэффективно для очень больших объемов.
    • ХранилищеЗначения способно хранить значительные объемы данных (до 2 ГБ), но операции чтения и десериализации больших объектов все равно будут требовать времени.
  2. Оптимизация получения GUID и производительность:
    • Использование запросов для получения списка GUID из справочника является наиболее эффективным способом, особенно для большого количества элементов. Это значительно быстрее, чем итерация по выборке элементов в цикле.
    • Для получения строкового представления GUID ссылки, кроме метода Ссылка.УникальныйИдентификатор(), можно использовать XMLСтрока(Ссылка). Этот метод возвращает строковое представление ссылки, которое включает в себя GUID, и может быть полезен в некоторых сценариях, хотя для получения именно объекта УникальныйИдентификатор предпочтительнее первый вариант.
  3. Функция ЗначениеВСтрокуВнутр():
    • В одном из сообщений форума упоминалась функция ЗначениеВСтрокуВнутр(). Важно понимать, что эта функция предназначена для получения внутреннего строкового представления объекта. Она часто используется для внутренней сериализации или в механизмах обмена данными.
    • Формат строки, возвращаемой этой функцией, является специфическим системным представлением и не предназначен для легкого чтения или программного разделения на отдельные GUID без знания внутренней структуры. Использование ЗначениеВСтрокуВнутр() для создания списка GUID, разделенных символом, может быть излишне сложным и менее прозрачным по сравнению с СтрСоединить(МассивГУИД, ";") или прямым сохранением массива. Мы рекомендуем избегать ее для данной задачи.

Мы рассмотрели различные варианты решения задачи по сбору GUIDов элементов справочника и их сохранению в константе ХранилищеЗначения. Выбор конкретного подхода зависит от ваших требований к формату хранения, производительности и удобству дальнейшей работы с данными.

В заключение, для поставленной задачи наиболее оптимальными и современными подходами являются:

  1. Формирование массива GUID с помощью запроса: Это наиболее быстрый и эффективный способ получить исходные GUIDы.
  2. Прямое сохранение Массива или СпискаЗначений в ХранилищеЗначения: Этот подход упрощает код, сохраняет исходный тип УникальныйИдентификатор и позволяет избежать ручного формирования и парсинга строки с разделителями. Он предпочтительнее, чем хранение одной длинной строки, если нет специфических требований к строковому формату.
  3. Если в будущем возможно расширение данных, хранящихся для каждой платформы, стоит рассмотреть использование ТаблицыЗначений.

Надеемся, что этот подробный разбор поможет вам в вашей работе с платформой 1С:Предприятие!

← К списку