Как получить значение дополнительного реквизита или сведения в 1С 8.3?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

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

Разница между дополнительными реквизитами и дополнительными сведениями

Прежде чем писать код получения данных, проанализируем структуру их хранения. В типовых конфигурациях (1С:Бухгалтерия предприятия, 1С:Управление торговлей, 1С:ERP, 1С:Комплексная автоматизация, 1С:УНФ) свойства разделены на две принципиально разные категории:

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

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

Способ 1. Получение дополнительного сведения через прямой запрос к регистру сведений

Если вам требуется получить значение дополнительного сведения, созданного для документа, обратимся к регистру сведений ДополнительныеСведения. Рассмотрим типовой пример запроса и разберем частые ошибки при обработке его результатов.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |	ДополнительныеСведения.Свойство КАК Свойство,
    |	ДополнительныеСведения.Значение КАК Значение
    |ИЗ
    |	РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
    |ГДЕ
    |	ДополнительныеСведения.Объект = &Объект
    |	И ДополнительныеСведения.Свойство = &Свойство";

Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект);
Запрос.УстановитьПараметр("Свойство", ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Спецификация"));

РезультатЗапроса = Запрос.Выполнить();

// Правильный обход выборки:
Выборка = РезультатЗапроса.Выбрать();
Если Выборка.Следующий() Тогда
    ЗначениеСпецификации = Выборка.Значение;
Иначе
    ЗначениеСпецификации = "";
КонецЕсли;

Важные нюансы и ошибки, на которые стоит обратить внимание:

  1. Пропуск метода Следующий(): После вызова метода Выбрать() указатель выборки находится перед первой записью. Попытка прочитать Выборка.Значение без предварительного вызова Выборка.Следующий() вернет Неопределено или пустое значение.
  2. Использование выгрузки в таблицу значений: Если выгружать результат через Выгрузить(), необходимо обязательно контролировать количество строк через условие Если ТаблицаРезультата.Количество() > 0 Тогда, иначе обращение по индексу ТаблицаРезультата[0] приведет к аварийному завершению программы при отсутствии записи.
  3. Проверка входных параметров: При разработке печатных форм входной параметр МассивОбъектов всегда следует проверять на заполненность (МассивОбъектов.Количество() > 0), чтобы избежать ошибок выполнения.

Способ 2. Получение дополнительного реквизита из табличной части объекта

Если свойство создано как дополнительный реквизит (находится на форме документа), обращаться к регистру сведений бесполезно. В таком случае выполним запрос к табличной части документа:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |	ДокРеквизиты.Значение КАК Значение
    |ИЗ
    |	Документ.РеализацияТоваровУслуг.ДополнительныеРеквизиты КАК ДокРеквизиты
    |ГДЕ
    |	ДокРеквизиты.Ссылка = &Объект
    |	И ДокРеквизиты.Свойство = &Свойство";

Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект);
Запрос.УстановитьПараметр("Свойство", ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Спецификация"));

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
    ЗначениеСпецификации = Выборка.Значение;
КонецЕсли;

Способ 3. Использование готовых функций БСП (рекомендуемый универсальный подход)

В конфигурациях, использующих Библиотеку стандартных подсистем, нет необходимости писать запросы вручную для точечного получения значений. В общем модуле УправлениеСвойствами предусмотрены готовые экспортные методы, которые самостоятельно определяют, где хранится свойство (в реквизитах или сведениях), и возвращают его значение.

Посмотрим на пример получения единичного значения:


СвойствоСпецификация = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Спецификация");

// Функция сама определит место хранения и вернет значение
ЗначениеСпецификации = УправлениеСвойствами.ЗначениеСвойства(СсылкаНаОбъект, СвойствоСпецификация);

Если для объекта требуется получить сразу несколько свойств, воспользуемся чтением набора значений:


// Получение всех свойств объекта в виде таблицы значений:
ТаблицаСвойств = УправлениеСвойствами.ПрочитатьСвойстваИЗначения(СсылкаНаОбъект);

// Получение определенных свойств через массив:
МассивСвойств = Новый Массив;
МассивСвойств.Добавить(Свойство1);
МассивСвойств.Добавить(Свойство2);

СтруктураЗначений = УправлениеСвойствами.ЗначенияСвойств(СсылкаНаОбъект, МассивСвойств);

Способ 4. Оптимальное соединение в основном запросе печатной формы

Если вы разрабатываете печатную форму с возможностью групповой печати по нескольким документам сразу, вызывать функции или отдельные запросы в цикле неэффективно. Оптимальный вариант — присоединить дополнительное свойство прямо в основном запросе выборки данных через ЛЕВОЕ СОЕДИНЕНИЕ.

Рассмотрим пример формирования запроса для пакета документов:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |	Док.Ссылка КАК Ссылка,
    |	Док.Номер КАК НомерДок,
    |	Док.Дата КАК ДатаДок,
    |	Док.ДоговорКонтрагента.Номер КАК НомерДог,
    |	Док.ДоговорКонтрагента.Дата КАК ДатаДог,
    |	ЕСТЬNULL(ДопСведения.Значение, """") КАК Спецификация
    |ИЗ
    |	Документ.РеализацияТоваровУслуг КАК Док
    |	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК ДопСведения
    |		ПО ДопСведения.Объект = Док.Ссылка
    |		И ДопСведения.Свойство = &СвойствоСпецификация
    |ГДЕ
    |	Док.Ссылка В(&МассивОбъектов)";

Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
Запрос.УстановитьПараметр("СвойствоСпецификация", ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Спецификация"));

ВыборкаДокументы = Запрос.Выполнить().Выбрать();
Пока ВыборкаДокументы.Следующий() Цикл
    ОбластьШапка.Параметры.Заполнить(ВыборкаДокументы);
    ОбластьШапка.Параметры.ДатаДок = Формат(ВыборкаДокументы.ДатаДок, "ДЛФ=DD");
    ОбластьШапка.Параметры.ДатаДог = Формат(ВыборкаДокументы.ДатаДог, "ДЛФ=DD");
    ТабличныйДокумент.Вывести(ОбластьШапка);
КонецЦикла;

Практические рекомендации по надежности кода

  1. Откажитесь от жесткого поиска по наименованию: Метод НайтиПоНаименованию("Спецификация") уязвим к переименованию реквизита пользователем. В БСП у свойств присутствует реквизит Имя (имя для разработчиков). Искать элемент надежнее по связке Имя и набора свойств объекта, либо передавать ссылку через настройки обработки.
  2. Приведение типов в запросе: Поле Значение в регистре сведений и табличной части имеет составной тип данных. Если в печатной форме ожидается конкретный ссылочный тип, рекомендуется использовать конструкцию ВЫРАЗИТЬ(ДопСведения.Значение КАК Справочник.Номенклатура) для оптимизации производительности СУБД.
  3. Обработка отсутствующих значений: Всегда оборачивайте соединяемые поля в функцию ЕСТЬNULL(), чтобы не получать значение NULL в параметрах макета.
← На главную