Как получить значение дополнительного реквизита из результата запроса и передать его в объект

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Анализ структуры хранения дополнительных реквизитов

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

  1. Свойство — ссылка на элемент плана видов характеристик ДополнительныеРеквизитыИСведения.
  2. Значение — само значение реквизита (может быть разного типа: строка, число, дата или ссылка).

Основная сложность заключается в том, что у разных позиций номенклатуры может быть разный набор заполненных свойств. Именно поэтому обращение к результату запроса через индекс (например, Результат[3]) является грубой ошибкой: сегодня под третьим индексом находится «Цвет», а завтра для другого товара там окажется «Материал» или вовсе пустота.

Способ 1. Использование пакетного запроса и поиска в таблице значений

Рассмотрим классический способ получения данных через запрос. Мы будем использовать пакетный запрос, чтобы одним обращением к серверу получить и основные реквизиты объекта, и его дополнительные свойства.


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

Запрос.УстановитьПараметр("Ссылка", Объект.ЗаполнитьНаОсновании);

РезультатПакета = Запрос.ВыполнитьПакет();
ТЗ_Основные = РезультатПакета[0].Выгрузить();
ТЗ_ДопРеквизиты = РезультатПакета[1].Выгрузить();

// Заполняем основные реквизиты
Если ТЗ_Основные.Количество() > 0 Тогда
    ЗаполнитьЗначенияСвойств(Объект, ТЗ_Основные[0]);
КонецЕсли;

Теперь выясним, как сопоставить данные из ТЗ_ДопРеквизиты с конкретными реквизитами нашего справочника. Вместо перебора в цикле или обращения по индексу, мы воспользуемся методом Найти(). Но помните: искать нужно по ссылке на свойство, а не по его строковому имени.


// Определим ссылки на нужные нам свойства (лучше это делать один раз заранее)
СвойствоЗаголовок = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Заголовок товара (SEO)");
СвойствоОписание = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Описание товара (SEO)");

// Ищем конкретные значения в полученной таблице
СтрокаЗаголовок = ТЗ_ДопРеквизиты.Найти(СвойствоЗаголовок, "Свойство");
Если СтрокаЗаголовок <> Неопределено Тогда
    Объект.ЗаголовокТовара = СтрокаЗаголовок.Значение;
КонецЕсли;

СтрокаОписание = ТЗ_ДопРеквизиты.Найти(СвойствоОписание, "Свойство");
Если СтрокаОписание <> Неопределено Тогда
    Объект.ОписаниеТовара = СтрокаОписание.Значение;
КонецЕсли;

Способ 2. «Плоский» запрос (оптимизация для производительности)

Если вам нужно заполнить много реквизитов объекта, поиск по таблице значений для каждого поля может замедлить работу. В этом случае проанализируем ситуацию и перестроим запрос так, чтобы он сразу вернул «плоскую» строку, где каждое свойство будет в отдельной колонке. Это делается с помощью конструкции МАКСИМУМ(ВЫБОР...).


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

Запрос.УстановитьПараметр("Номенклатура", Объект.ЗаполнитьНаОсновании);
Запрос.УстановитьПараметр("СвойствоSEO", СсылкаНаСвойствоSEO);
Запрос.УстановитьПараметр("СвойствоСинонимы", СсылкаНаСвойствоСинонимы);

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

Этот метод считается наиболее профессиональным, так как он минимизирует количество логических условий в коде 1С, перенося нагрузку на SQL-сервер. В результате выполнения такого запроса мы получаем готовую строку, которую можно передать в ЗаполнитьЗначенияСвойств.

Способ 3. Программный интерфейс БСП (самый простой)

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


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

Важный совет: Поиск свойств по наименованию через НайтиПоНаименованию может быть опасным, если пользователь переименует доп. реквизит в пользовательском режиме. Чтобы сделать код надежнее, рекомендуется использовать поиск по уникальному идентификатору (GUID) или по имени программного интерфейса, если оно задано в метаданных свойства.

Резюме по решению задачи

Для корректного переноса данных из дополнительных реквизитов в основные поля объекта мы выполнили следующие действия:

  1. Отказались от ненадежного обращения к результату по индексам.
  2. Использовали пакетный запрос для получения данных ТЧ ДополнительныеРеквизиты.
  3. Применили метод Найти() по ссылке на свойство для точного сопоставления данных.
  4. Рассмотрели оптимизированный запрос с группировкой для быстрого заполнения множества полей.

Выбор конкретного метода зависит от ваших задач: для массовой обработки данных выбирайте «плоский» запрос, а для простых манипуляций в форме — функции БСП.

← На главную