При разработке отчетов, обработок выгрузки на сайт или интеграций в среде 1С часто возникает необходимость массово получить значения дополнительных реквизитов объектов (например, справочника Номенклатура). Начинающие разработчики нередко сталкиваются со сложностями, когда пытаются анализировать форму элемента и видят там динамически сгенерированные реквизиты с длинными непонятными именами, содержащими UUID.
В этой статье мы подробно разберем, как устроена подсистема «Свойства» Библиотеки стандартных подсистем (БСП), почему на форме появляются странные идентификаторы и как правильно извлекать эти данные программно на сервере с помощью запросов и встроенных механизмов БСП.
Прежде чем перейти к написанию кода, давайте проанализируем внутреннее устройство подсистемы «Свойства». БСП разделяет все дополнительные свойства на две категории, которые хранятся принципиально в разных местах базы данных:
ДополнительныеРеквизиты. При каждом изменении такого свойства перезаписывается сам объект, меняется версия его данных и дата изменения.ДополнительныеСведения. Их редактирование не приводит к перезаписи и изменению версии самого объекта (что критически важно, например, при закрытых периодах или настроенной синхронизации данных).Именно из-за этого разделения часто возникает путаница. Если вы ищете дополнительные реквизиты номенклатуры в регистре сведений ДополнительныеСведения, запрос вернет пустой результат. Для номенклатуры их нужно искать непосредственно в ее табличной части.
Когда мы открываем форму номенклатуры в конфигураторе, мы не видим там полей вроде «Цвет», «Размер» или «Производитель». Эти элементы управления создаются платформой динамически в момент открытия формы. БСП выполняет следующие действия:
ДополнительныеРеквизитыИСведения.x) и добавляет префикс. Получается строка вида ДополнительныйРеквизитЗначение_8A949A3Cx9FBD....Пытаться получить данные через обращение к элементам формы в цикле или фоновом задании — грубая ошибка. Во-первых, на сервере в контексте выполнения запроса у нас просто нет доступа к форме. Во-вторых, завязываться на динамические UUID крайне ненадежно, так как при переносе данных или обновлении базы эти идентификаторы могут измениться.
Рассмотрим три правильных и надежных способа получения значений дополнительных реквизитов.
Если вам необходимо выгрузить данные по множеству позиций номенклатуры или построить отчет, оптимальным решением по производительности будет использование запроса к табличной части справочника. Этот метод работает максимально быстро, не инициализирует тяжелые объекты в памяти и отлично подходит для серверного кода.
Разберем пример запроса, который выбирает значение конкретного свойства для заданной номенклатуры:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НоменклатураДополнительныеРеквизиты.Ссылка КАК Номенклатура,
| НоменклатураДополнительныеРеквизиты.Значение КАК ЗначениеРеквизита
|ИЗ
| Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
|ГДЕ
| НоменклатураДополнительныеРеквизиты.Ссылка В(&МассивНоменклатуры)
| И НоменклатураДополнительныеРеквизиты.Свойство = &НужноеСвойство";
// В качестве параметра Свойство передается ссылка на элемент ПВХ ДополнительныеРеквизитыИСведения
Запрос.УстановитьПараметр("НужноеСвойство", ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Цвет (Номенклатура)"));
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивСсылок);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обрабатываем полученные данные
Сообщить("Для номенклатуры " + Выборка.Номенклатура + " установлено значение: " + Выборка.ЗначениеРеквизита);
КонецЦикла;
Важный нюанс: поиск свойства по наименованию через НайтиПоНаименованию() в реальном коде лучше заменить на поиск по коду, предопределенному имени или вынести выбор свойства в настройки (например, в параметры отчета или константы), чтобы избежать проблем при случайном переименовании свойства пользователем.
Если код выполняется на сервере и вам нужно получить значение свойства для одного конкретного объекта в процессе выполнения какой-либо бизнес-логики, рекомендуется использовать стандартный общий модуль БСП УправлениеСвойствами. Этот метод гарантирует совместимость при обновлениях конфигурации.
Для этого используется функция ЗначениеСвойства(). Посмотрим на практический пример:
// 1. Находим целевое свойство (элемент ПВХ)
СвойствоЦвет = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("ИмяДляРазработчиков", "Цвет_8A9499FB");
Если ЗначениеЗаполнено(СвойствоЦвет) Тогда
// 2. Получаем значение свойства для конкретной ссылки номенклатуры
ЗначениеРеквизита = УправлениеСвойствами.ЗначениеСвойства(СсылкаНаНоменклатуру, СвойствоЦвет);
// 3. Используем полученное значение в коде
Если ЗначениеРеквизита = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Красный") Тогда
// Выполняем необходимое действие...
КонецЕсли;
КонецЕсли;
Этот метод самостоятельно определит, где именно хранится свойство (в табличной части или в регистре сведений), и вернет актуальное значение. Вам не нужно задумываться о структуре хранения данных конкретного свойства.
Бывают ситуации, когда вам действительно необходимо получить значение дополнительного реквизита прямо на форме элемента в процессе интерактивной работы пользователя (например, при изменении другого поля на клиенте, когда объект еще не записан в базу данных). Как мы выяснили, обращаться напрямую к имени с UUID нельзя.
Для решения этой задачи разработчики БСП предусмотрели специальную служебную коллекцию на форме — таблицу Свойства_ОписаниеДополнительныхРеквизитов. В ней хранится карта соответствия между реальными свойствами (ссылками ПВХ) и динамическими именами элементов формы.
Проанализируем пример кода, который можно использовать в модуле управляемой формы для безопасного получения значения:
&НаКлиенте
Процедура ПолучитьЗначениеРеквизитаНаФорме()
// Определяем свойство, значение которого нам нужно прочитать
НужноеСвойство = ПолучитьСвойствоНа Сервере();
// Отыскиваем строку описания этого свойства в служебной коллекции формы
ПараметрыОтбора = Новый Структура("Свойство", НужноеСвойство);
НайденныеСтроки = Свойства_ОписаниеДополнительныхРеквизитов.НайтиСтроки(ПараметрыОтбора);
Если НайденныеСтроки.Количество() > 0 Тогда
СтрокаОписания = НайденныеСтроки[0];
// Получаем то самое динамическое имя реквизита формы с UUID
ИмяРеквизитаФормы = СтрокаОписания.ИмяРеквизитаЗначение;
// Обращаемся к реквизиту формы по его динамическому имени
ТекущееЗначениеНаФорме = ЭтотОбъект[ИмяРеквизитаФормы];
ПоказатьПредупреждение(, "Текущее значение на форме: " + ТекущееЗначениеНаФорме);
КонецЕсли;
КонецПроцедуры
Для эффективной работы с дополнительными реквизитами в конфигурациях на базе БСП (таких как «1С:Управление торговлей 11», «1С:ERP», «1С:Комплексная автоматизация») всегда придерживайтесь следующих правил:
ДополнительныеРеквизиты соответствующего справочника.УправлениеСвойствами.ЗначениеСвойства().Свойства_ОписаниеДополнительныхРеквизитов.