Приветствуем вас, коллеги-разработчики 1С! Сегодня мы с вами разберем очень практичную и часто встречающуюся задачу: как эффективно собрать список уникальных идентификаторов (GUID) элементов справочника, объединить их в строку с заданным разделителем и сохранить эту строку в константе с типом ХранилищеЗначения. Мы проанализируем различные подходы, начиная от простых циклов и заканчивая оптимизированными запросами, а также рассмотрим альтернативные способы хранения данных.
Представим, что у нас есть конфигурация с существующим справочником «Платформы», который содержит реквизиты: Наименование, ЧисловойКод и Ключевая (булево). Также в конфигурации присутствует константа «ПлатформыРезерв» с типом данных ХранилищеЗначения. Наша цель — поместить в эту константу строку, состоящую из GUID всех или некоторых элементов справочника «Платформы», разделенных символом точка с запятой (;).
Давайте выясним, как лучше всего решить эту задачу, учитывая производительность, удобство поддержки и возможности дальнейшего расширения.
Начнем с классического подхода, который часто приходит на ум первым и был предложен в исходной теме. Мы будем итерироваться по элементам справочника, собирать их уникальные идентификаторы в массив, а затем объединять элементы массива в одну строку с помощью специальной функции.
Разберем по шагам, как это реализовать:
Массив, который будет хранить наши GUIDы.Ссылка.УникальныйИдентификатор() и добавляем его в наш массив.СтрСоединить(), чтобы объединить все элементы массива в одну строку, используя в качестве разделителя точку с запятой (;).Посмотрим на пример кода для этого подхода:
// Создаем новый массив для хранения GUID
МассивГУИД = Новый Массив;
// Получаем ссылку на справочник "Платформы"
СправочникПлатформы = Справочники.Платформы;
// Выполняем выборку всех элементов справочника
Выборка = СправочникПлатформы.Выбрать();
// Обходим выборку и добавляем GUIDы в массив
Пока Выборка.Следующий() Цикл
МассивГУИД.Добавить(Выборка.Ссылка.УникальныйИдентификатор());
КонецЦикла;
// Объединяем элементы массива в строку, используя ";" как разделитель
СтрокаГУИД = СтрСоединить(МассивГУИД, ";");
// Сохраняем полученную строку в константу "ПлатформыРезерв"
Константы.ПлатформыРезерв.Установить(СтрокаГУИД);
Этот способ прост и понятен, но для справочников с очень большим количеством элементов он может быть не самым производительным, поскольку мы выполняем итерацию по каждому элементу на стороне 1С-клиента или сервера приложений.
Когда речь идет о работе с большими объемами данных, всегда стоит рассмотреть использование запросов к базе данных. Запросы выполняются на стороне СУБД, что значительно быстрее, чем итерации в цикле на стороне 1С. Мы можем поручить СУБД собрать все необходимые GUIDы и вернуть нам их уже в виде удобного объекта.
Проанализируем ситуацию: нам нужны только уникальные идентификаторы ссылок. Запрос идеально подходит для этой цели. Мы можем использовать функцию УНИКАЛЬНЫЙИДЕНТИФИКАТОР() непосредственно в тексте запроса.
Посмотрим на пример кода, который использует объект Запрос:
// Создаем новый объект Запрос
Запрос = Новый Запрос;
// Формируем текст запроса: выбираем уникальные идентификаторы ссылок
Запрос.Текст =
"ВЫБРАТЬ
| УНИКАЛЬНЫЙИДЕНТИФИКАТОР(СправочникПлатформы.Ссылка) КАК GUID
|ИЗ
| Справочник.Платформы КАК СправочникПлатформы";
// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
// Выгружаем колонку "GUID" в массив
МассивГУИД = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("GUID");
// Объединяем элементы массива в строку
СтрокаГУИД = СтрСоединить(МассивГУИД, ";");
// Сохраняем полученную строку в константу
Константы.ПлатформыРезерв.Установить(СтрокаГУИД);
Этот подход значительно более эффективен, особенно для больших справочников. Мы минимизируем количество операций на стороне 1С, перекладывая основную нагрузку на СУБД.
Дополнительно, если нам нужно собрать GUIDы только тех платформ, у которых установлен реквизит Ключевая в значение Истина, мы можем легко модифицировать запрос, добавив условие ГДЕ:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| УНИКАЛЬНЫЙИДЕНТИФИКАТОР(СправочникПлатформы.Ссылка) КАК GUID
|ИЗ
| Справочник.Платформы КАК СправочникПлатформы
|ГДЕ
| СправочникПлатформы.Ключевая = ИСТИНА";
РезультатЗапроса = Запрос.Выполнить();
МассивГУИД = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("GUID");
СтрокаГУИД = СтрСоединить(МассивГУИД, ";");
Константы.ПлатформыРезерв.Установить(СтрокаГУИД);
Таким образом, использование запросов является наиболее рекомендуемым способом для получения списка GUIDов.
Теперь рассмотрим подход, который не был явно предложен в исходной теме, но является очень мощным и гибким благодаря возможностям типа ХранилищеЗначения. Вместо того чтобы преобразовывать массив GUID в строку с разделителем, мы можем напрямую сохранить объект Массив или СписокЗначений, содержащий объекты типа УникальныйИдентификатор, в константе ХранилищеЗначения.
Почему этот подход может быть лучше? Давайте рассмотрим подробнее:
СтрСоединить() при записи и СтрРазделить() (или другой парсинг) при чтении. ХранилищеЗначения само сериализует и десериализует объект.УникальныйИдентификатор, а не их строковое представление. Это позволяет напрямую использовать их, например, для получения ссылки на объект: Справочники.Платформы.ПолучитьСсылку(ГУИД).СписокЗначений, где в качестве значений будут храниться УникальныйИдентификатор, а в качестве представлений —, например, наименования.Недостатки такого подхода:
Посмотрим на пример кода для прямого сохранения Массива:
// Создаем новый объект Запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СправочникПлатформы.Ссылка.УникальныйИдентификатор КАК GUID
|ИЗ
| Справочник.Платформы КАК СправочникПлатформы";
// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
// Выгружаем колонку "GUID" в массив.
// Важно: здесь мы получаем объекты УникальныйИдентификатор, а не строки!
МассивГУИД = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("GUID");
// Сохраняем весь массив в константу "ПлатформыРезерв"
// ХранилищеЗначения автоматически сериализует массив
Константы.ПлатформыРезерв.Установить(МассивГУИД);
Для чтения данных из константы и использования их, код будет выглядеть так:
// Получаем хранимый объект из константы
// ХранилищеЗначения автоматически десериализует объект в исходный тип (Массив)
МассивГУИДИзКонстанты = Константы.ПлатформыРезерв.Получить();
// Проверяем, что объект получен и является массивом
Если ТипЗнч(МассивГУИДИзКонстанты) = Тип("Массив") Тогда
Для Каждого ТекущийГУИД Из МассивГУИДИзКонстанты Цикл
// ТекущийГУИД уже является объектом УникальныйИдентификатор
// Мы можем напрямую использовать его, например, для получения ссылки:
СсылкаПлатформы = Справочники.Платформы.ПолучитьСсылку(ТекущийГУИД);
Если СсылкаПлатформы.Пустая() Тогда
// Обработка случая, когда ссылка не найдена
Сообщить("Платформа с GUID " + ТекущийГУИД + " не найдена.");
Иначе
Сообщить("Найдена платформа: " + СсылкаПлатформы.Наименование);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если мы хотим использовать СписокЗначений, процесс аналогичен:
// Создаем новый объект Запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СправочникПлатформы.Ссылка.УникальныйИдентификатор КАК GUID,
| СправочникПлатформы.Наименование КАК Наименование
|ИЗ
| Справочник.Платформы КАК СправочникПлатформы";
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
СписокПлатформ = Новый СписокЗначений;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
СписокПлатформ.Добавить(ВыборкаДетальныеЗаписи.GUID, ВыборкаДетальныеЗаписи.Наименование);
КонецЦикла;
Константы.ПлатформыРезерв.Установить(СписокПлатформ);
И чтение:
СписокПлатформИзКонстанты = Константы.ПлатформыРезерв.Получить();
Если ТипЗнч(СписокПлатформИзКонстанты) = Тип("СписокЗначений") Тогда
Для Каждого ЭлементСписка Из СписокПлатформИзКонстанты Цикл
Сообщить("Платформа: " + ЭлементСписка.Представление + ", GUID: " + ЭлементСписка.Значение);
КонецЦикла;
КонецЕсли;
Этот подход предпочтителен, если нет строгих требований к хранению GUID именно в виде строки с разделителями, так как он более гибок и менее подвержен ошибкам.
Если в будущем потребуется хранить не только GUID, но и другую информацию о платформах (например, значение реквизита "Ключевая", "Наименование", или "ЧисловойКод"), то ТаблицаЗначений будет наиболее структурированным и удобным способом. Мы можем создать ТаблицаЗначений с нужными колонками, заполнить ее и сохранить целиком в ХранилищеЗначения.
Рассмотрим пример, как это сделать:
// Создаем новый объект Запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СправочникПлатформы.Ссылка.УникальныйИдентификатор КАК GUID,
| СправочникПлатформы.Наименование КАК Наименование,
| СправочникПлатформы.Ключевая КАК Ключевая
|ИЗ
| Справочник.Платформы КАК СправочникПлатформы";
// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
// Выгружаем результат запроса в ТаблицуЗначений
ТаблицаПлатформ = РезультатЗапроса.Выгрузить();
// Сохраняем ТаблицуЗначений в константу "ПлатформыРезерв"
Константы.ПлатформыРезерв.Установить(ТаблицаПлатформ);
Для чтения и использования данных из ТаблицыЗначений:
// Получаем ТаблицуЗначений из константы
ТаблицаПлатформИзКонстанты = Константы.ПлатформыРезерв.Получить();
// Проверяем, что объект получен и является ТаблицейЗначений
Если ТипЗнч(ТаблицаПлатформИзКонстанты) = Тип("ТаблицаЗначений") Тогда
Для Каждого СтрокаТЗ Из ТаблицаПлатформИзКонстанты Цикл
Сообщить("Платформа: " + СтрокаТЗ.Наименование
+ ", GUID: " + СтрокаТЗ.GUID
+ ", Ключевая: " + СтрокаТЗ.Ключевая);
// Можем использовать GUID для получения ссылки
СсылкаПлатформы = Справочники.Платформы.ПолучитьСсылку(СтрокаТЗ.GUID);
// ... дальнейшая работа со ссылкой
КонецЦикла;
КонецЕсли;
Данный подход является наиболее масштабируемым и удобным для хранения разнородных данных о списках объектов.
Давайте проанализируем некоторые важные аспекты, касающиеся использования ХранилищаЗначения и оптимизации:
ХранилищаЗначения:
ХранилищеЗначения предназначено для хранения значений различных типов в сериализованном (бинарном) виде, часто со сжатием данных. Это позволяет экономить место для больших объектов.ХранилищеЗначения, не поддерживают индексирование. По таким полям нельзя напрямую упорядочивать данные в запросах, выполнять поиск или фильтрацию. Если вам потребуется часто искать или фильтровать элементы по GUIDам, хранящимся в константе, то каждый раз придется извлекать весь список из ХранилищаЗначения и обрабатывать его в коде, что может быть неэффективно для очень больших объемов.ХранилищеЗначения способно хранить значительные объемы данных (до 2 ГБ), но операции чтения и десериализации больших объектов все равно будут требовать времени.Ссылка.УникальныйИдентификатор(), можно использовать XMLСтрока(Ссылка). Этот метод возвращает строковое представление ссылки, которое включает в себя GUID, и может быть полезен в некоторых сценариях, хотя для получения именно объекта УникальныйИдентификатор предпочтительнее первый вариант.ЗначениеВСтрокуВнутр():
ЗначениеВСтрокуВнутр(). Важно понимать, что эта функция предназначена для получения внутреннего строкового представления объекта. Она часто используется для внутренней сериализации или в механизмах обмена данными.ЗначениеВСтрокуВнутр() для создания списка GUID, разделенных символом, может быть излишне сложным и менее прозрачным по сравнению с СтрСоединить(МассивГУИД, ";") или прямым сохранением массива. Мы рекомендуем избегать ее для данной задачи.Мы рассмотрели различные варианты решения задачи по сбору GUIDов элементов справочника и их сохранению в константе ХранилищеЗначения. Выбор конкретного подхода зависит от ваших требований к формату хранения, производительности и удобству дальнейшей работы с данными.
В заключение, для поставленной задачи наиболее оптимальными и современными подходами являются:
Массива или СпискаЗначений в ХранилищеЗначения: Этот подход упрощает код, сохраняет исходный тип УникальныйИдентификатор и позволяет избежать ручного формирования и парсинга строки с разделителями. Он предпочтительнее, чем хранение одной длинной строки, если нет специфических требований к строковому формату.ТаблицыЗначений.Надеемся, что этот подробный разбор поможет вам в вашей работе с платформой 1С:Предприятие!
← К списку