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