Как правильно сохранить двоичные данные в регистр сведений при записи из формы

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

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

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

Суть проблемы и архитектурные особенности

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

Рассмотрим ситуацию: у нас есть регистр ХранилищеФайловДокументов с измерением Документ и ресурсом ДанныеЗагруженогоФайла. Нам необходимо загрузить файл через диалог и сохранить его.

Шаг 1. Выбор файла и помещение во временное хранилище

Первым делом нам нужно получить данные с локального компьютера пользователя. В современных конфигурациях крайне рекомендуется использовать асинхронные методы, чтобы не блокировать интерфейс и обеспечить работу в веб-клиенте. Если же файлы должны поступать в систему из внешних источников, используется программа для автоматического сбора данных из почты, FTP и HTTP.

Разберем алгоритм: мы не просто получаем двоичные данные, а сразу помещаем их во Временное хранилище. Это специальная область памяти на сервере, доступ к которой осуществляется по уникальному адресу-строке.

Для этого на форме нам понадобится реквизит (переменная) с типом Строка, например, АдресФайлаВоВременномХранилище. Посмотрим на пример кода выбора файла:


&НаКлиенте
Асинхронная Процедура ЗагрузитьФайл(Команда)
    
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Все файлы (*.*)|*.*";
    
    // Используем асинхронный метод выбора
    ВыбранныеФайлы = Ждать Диалог.ВыбратьАсинх();
    
    Если ВыбранныеФайлы <> Неопределено Тогда
        ПутьКФайлу = ВыбранныеФайлы[0];
        
        // Помещаем файл во временное хранилище
        РезультатПомещения = Ждать ПоместитьФайлНаСерверАсинх(,,, ПутьКФайлу, УникальныйИдентификатор);
        
        Если РезультатПомещения <> Неопределено Тогда
            // Сохраняем адрес в реквизит формы для последующей записи
            АдресФайлаВоВременномХранилище = РезультатПомещения.Адрес;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Запись данных в объект на сервере

Когда пользователь нажимает кнопку «Записать и закрыть», срабатывают стандартные механизмы платформы. Чтобы наши данные из временного хранилища попали в ресурс регистра, нам нужно перехватить процесс записи на сервере. Для этого идеально подходит обработчик события формы ПередЗаписьюНаСервере.

Важный нюанс: часто разработчики пытаются манипулировать параметрами записи или напрямую обращаться к реквизитам формы. Правильный подход — изменять непосредственно ТекущийОбъект, который платформа подготовила для записи в базу данных.

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


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Проверяем, был ли выбран новый файл (заполнен ли адрес)
    Если ЭтоАдресВременногоХранилища(АдресФайлаВоВременномХранилище) Тогда
        
        // Получаем двоичные данные из хранилища по адресу
        ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайлаВоВременномХранилище);
        
        // Помещаем данные в ресурс объекта через конструктор ХранилищеЗначения
        // Второй параметр "Новый СжатиеДанных(9)" позволяет оптимизировать размер БД
        ТекущийОбъект.ДанныеЗагруженогоФайла = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
        
        // После извлечения данных адрес можно очистить, 
        // но платформа сделает это сама при закрытии формы
        УдалитьИзВременногоХранилища(АдресФайлаВоВременномХранилище);
        АдресФайлаВоВременномХранилище = "";
        
    КонецЕсли;
    
КонецПроцедуры

Анализ типичных ошибок

Проанализируем ситуацию, описанную в сообщениях форума, где автор жаловался, что «ничего не происходит».

  1. Попытка вызова серверной процедуры вручную из ПередЗаписью: В сообщении №2 пользователь пытался сам вызвать ПередЗаписьюНаСервере. Это грубая ошибка. Данный обработчик должен вызываться самой платформой. Для этого нужно зайти в свойства формы, найти событие «Перед записью на сервере» и нажать на лупу, чтобы создать корректную связь (делегат).
  2. Использование ПараметрыЗаписи для передачи данных: Коллекция ПараметрыЗаписи предназначена для передачи инструкций (флагов) о том, как записывать, а не что записывать. Для изменения данных записи нужно использовать ТекущийОбъект.
  3. Пустые двоичные данные: Как выяснилось в сообщении №8, проблема часто бывает банальной — метод ПолучитьДвоичныеДанные() возвращал пустой объект. Всегда добавляйте проверку на размер полученных данных перед созданием ХранилищеЗначения.
  4. Отсутствие измерения: Если вы создаете новую запись регистра, убедитесь, что измерение (в нашем случае Документ) заполнено. Без ключевых полей (измерений) 1С не сможет создать уникальную запись в таблице регистра.

Оптимизация хранения: Хранилище или тома на диске?

Хранение файлов в регистре сведений удобно тем, что данные всегда попадают в бэкап всей базы. Однако при больших объемах (терабайты данных) база начинает «тормозить», а регламентные операции (индексация, ТИС) длятся вечно. Чтобы регламентное обслуживание не мешало работе пользователей, можно настроить автоматическое тестирование и архивацию баз 1С по расписанию.

Выясним, какие есть альтернативы:

Подведем итог: для успешного сохранения файла в регистр сведений необходимо использовать связку Клиент (выбор и помещение во временное хранилище) -> Сервер (получение из хранилища и запись в ТекущийОбъект). Именно такая схема гарантирует стабильную работу управляемого приложения.

← На главную