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