Работа с константами, имеющими тип ХранилищеЗначения, часто вызывает вопросы у начинающих разработчиков. В отличие от примитивных типов (строка, число, булево), данные в хранилище упакованы (сериализованы) в двоичный формат. Это означает, что мы не можем просто обратиться к содержимому и выполнить команду "удалить элемент", используя язык запросов или простые методы обращения через точку.
Давайте разберем подробно, как правильно извлекать, модифицировать и записывать обратно сложные структуры данных (например, Массивы или Таблицы Значений), сохраненные в константе.
Прежде чем приступать к коду, определим последовательность действий. Поскольку данные внутри константы "законсервированы", изменить их "на лету" невозможно. Похожий принцип используется, когда требуется очистка хранилища настроек пользователей. Алгоритм действий всегда выглядит так:
Рассмотрим пример из обсуждения. Допустим, у нас есть константа ПлатформыРезерв (или НоваяКонстанта), в которой хранится массив ссылок на справочник "Клиенты". Чтобы начать работу с этими данными, нам нужно их "достать".
Обратите внимание на синтаксис. Простого обращения к менеджеру констант недостаточно.
// Получаем само значение константы (объект типа ХранилищеЗначения)
Хранилище = Константы.ПлатформыРезерв.Получить();
// Если константа пустая, метод вернет Неопределено
Если Хранилище = Неопределено Тогда
Возврат; // Или инициализируем новый массив
КонецЕсли;
// Извлекаем данные из хранилища в переменную
МассивСсылок = Хранилище.Получить();
Частая ошибка — забыть второй вызов метода Получить().
Первый Получить() обращается к базе данных и возвращает объект-контейнер.
Второй Получить() (метод объекта ХранилищеЗначения) распаковывает данные и возвращает конкретный тип (в нашем случае Массив).
В одной строке это выглядит так:
МассивСсылок = Константы.ПлатформыРезерв.Получить().Получить();
Задача автора: удалить из массива ссылки на клиентов, у которых реквизит "Ключевой" имеет значение Ложь. Поскольку мы выгрузили данные в переменную МассивСсылок, мы работаем с обычным массивом 1С в оперативной памяти.
Важное правило при удалении из коллекций: Если вы перебираете коллекцию циклом и удаляете элементы, всегда идите с конца (обратный цикл). Это особенно актуально, когда производится поиск и замена битых ссылок. Если идти с начала, индексы сместятся после первого удаления, и вы пропустите элементы или получите ошибку выхода за границы массива.
Рассмотрим правильный код очистки массива:
// Получаем верхнюю границу массива для обратного цикла
Индекс = МассивСсылок.ВГраница();
// Цикл Пока, так как мы будем уменьшать Индекс вручную
Пока Индекс >= 0 Цикл
ТекущаяСсылка = МассивСсылок[Индекс];
// Проверяем условие. Нам нужно удалить тех, кто НЕ ключевой.
// Обращение к реквизитам через точку допустимо, но помните о производительности
// (в идеале такие данные лучше получать запросом, но здесь массив уже в памяти).
Если НЕ ТекущаяСсылка.Ключевой Тогда
МассивСсылок.Удалить(Индекс);
КонецЕсли;
// Переходим к предыдущему элементу
Индекс = Индекс - 1;
КонецЦикла;
Альтернативный, часто более быстрый способ — создать новый массив и поместить туда только "нужные" элементы, а затем перезаписать старый массив.
НовыйМассив = Новый Массив;
Для Каждого ЭлементСсылка Из МассивСсылок Цикл
Если ЭлементСсылка.Ключевой Тогда
НовыйМассив.Добавить(ЭлементСсылка);
КонецЕсли;
КонецЦикла;
// Теперь НовыйМассив содержит только правильных клиентов
МассивСсылок = НовыйМассив;
Теперь, когда переменная МассивСсылок содержит актуальные данные, нам нужно поместить её обратно в базу данных. Для этого мы должны создать новый объект ХранилищеЗначения. Напрямую присвоить массив константе нельзя.
// Упаковываем массив в хранилище
// Можно использовать сжатие для экономии места, если массив большой
НовоеХранилище = Новый ХранилищеЗначения(МассивСсылок, Новый СжатиеДанных(9));
// Записываем в константу
Константы.ПлатформыРезерв.Установить(НовоеХранилище);
Соберем все части вместе, чтобы решить задачу автора по удалению не ключевых клиентов из константы.
// 1. Чтение
ТекущееЗначение = Константы.ПлатформыРезерв.Получить();
Если ТипЗнч(ТекущееЗначение) <> Тип("ХранилищеЗначения") Тогда
Сообщить("В константе нет хранилища!");
Возврат;
КонецЕсли;
ИсходныйМассив = ТекущееЗначение.Получить();
Если ТипЗнч(ИсходныйМассив) <> Тип("Массив") Тогда
Сообщить("В хранилище лежит не массив!");
Возврат;
КонецЕсли;
// 2. Обработка (фильтрация)
ОтфильтрованныйМассив = Новый Массив;
Для Каждого СсылкаНаКлиента Из ИсходныйМассив Цикл
// Проверка на "битую" ссылку и на признак
Если ЗначениеЗаполнено(СсылкаНаКлиента)
И СсылкаНаКлиента.Ключевой = Истина Тогда
ОтфильтрованныйМассив.Добавить(СсылкаНаКлиента);
КонецЕсли;
КонецЦикла;
// 3. Запись
НовоеХранилище = Новый ХранилищеЗначения(ОтфильтрованныйМассив);
Константы.ПлатформыРезерв.Установить(НовоеХранилище);
Сообщить("Список обновлен. Осталось элементов: " + ОтфильтрованныйМассив.Количество());
Хотя технически хранение списков ссылок в константе типа ХранилищеЗначения возможно, в профессиональной разработке 1С это считается плохой практикой (антипаттерном) по нескольким причинам:
Для хранения списков значений, которые нужно фильтровать и обрабатывать, рекомендуется использовать Регистры сведений или табличные части соответствующих справочников.