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