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