Как работать с типом ХранилищеЗначения в табличной части без немедленной записи объекта в базу данных

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

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

Почему ХранилищеЗначения не сохраняется в данных формы

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

Если мы создаем Новый ХранилищеЗначения(Данные) внутри серверной процедуры и не вызываем ДокументОбъект.Записать(), то после завершения процедуры и возврата на клиент ссылка на этот объект в памяти сервера уничтожается, а в реквизите формы остается пустота. Чтобы обойти это ограничение, нам необходимо использовать механизм Временного хранилища.

Метод 1: Использование адресов временного хранилища в строках ТЧ

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

Разберем реализацию по шагам:

  1. Добавим в табличную часть (на уровне метаданных или только в реквизиты формы) строковый реквизит, например, АдресФайла с достаточной длиной.
  2. При выборе файла на клиенте мы помещаем его во временное хранилище и записываем полученный адрес в текущую строку.
  3. Окончательную запись файла в реальное ХранилищеЗначения выполняем только в момент стандартной записи документа.

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


&НаКлиенте
Процедура ЗагрузитьФайлВСтроку(Команда)
    
    ТекущиеДанные = Элементы.Документация.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Описание оповещения после выбора файла
    Оповещение = Новый ОписаниеОповещения("ЗагрузитьФайлЗавершение", ЭтотОбъект);
    
    // Используем современный метод помещения файла
    ПараметрыЗагрузки = Новый ПараметрыПомещенияФайлов;
    НачатьПомещениеФайлаНаСервер(Оповещение, , , , ПараметрыЗагрузки, ЭтаФорма.УникальныйИдентификатор);

КонецПроцедуры

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

Теперь выясним причину, почему данные не пропадут. Указывая ЭтаФорма.УникальныйИдентификатор в методе помещения файла, мы гарантируем, что платформа будет хранить эти двоичные данные в памяти сервера до тех пор, пока пользователь не закроет форму документа.

Синхронизация данных перед записью в базу

Теперь нам необходимо перенести данные из временного хранилища в реальный реквизит объекта. Лучшее место для этого — обработчик события формы ПередЗаписьюНаСервере. Рассмотрим, как это сделать правильно:


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

Важный момент: в обработчике ПередЗаписьюНаСервере мы работаем напрямую с ТекущийОбъект. Это именно тот экземпляр объекта метаданных, который через мгновение будет записан в базу данных. Все изменения, внесенные в него здесь, попадут в СУБД.

Альтернативный вариант: Работа с ДвоичнымиДанными в реквизитах формы

Выясним, существует ли другой способ. Можно создать в табличной части формы реквизит с типом Произвольный. На сервере в этот реквизит можно поместить объект типа ДвоичныеДанные. В отличие от ХранилищеЗначения, двоичные данные могут «жить» в контексте формы при передаче между сервером и сервером (но не на клиенте). Однако этот метод более трудозатратен в плане ручного управления контекстом и может приводить к избыточному потреблению оперативной памяти сервера приложений, так как файлы будут дублироваться в структуре данных формы.

Оптимизация и работа с памятью

Проанализируем ситуацию с точки зрения производительности. Если ваша табличная часть предполагает хранение десятков тяжелых файлов (например, сканы чертежей по 50 Мб), использование временного хранилища может привести к переполнению оперативной памяти (RAM) на сервере 1С. В таких случаях мы рекомендуем:

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

Резюме решения

Подведем итог нашему разбору. Для реализации отложенного сохранения файлов в ХранилищеЗначения необходимо:

  1. Отказаться от попыток напрямую записывать ХранилищеЗначения в Объект до момента финального сохранения.
  2. Использовать строковую колонку для временных адресов.
  3. Применять УникальныйИдентификатор формы для фиксации данных в памяти.
  4. Выполнять финальную сборку объекта ХранилищеЗначения в процедуре ПередЗаписьюНаСервере.

Такой подход гарантирует целостность данных и стабильную работу приложения в клиент-серверном режиме.

← На главную