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