При работе с типовыми и нетиповыми конфигурациями 1С на платформе «1С:Предприятие 8.3» часто возникает задача найти элемент справочника (например, номенклатуру) по значению его дополнительного реквизита. Попытка использовать стандартный метод НайтиПоРеквизиту() в этом случае приводит к ошибке. Разберем подробнее, почему так происходит, как правильно устроено хранение дополнительных реквизитов и как корректно составить запрос для поиска.
Выясним причину, по которой стандартный метод менеджера справочника не работает для дополнительных реквизитов:
НайтиПоРеквизиту() предназначен исключительно для работы с реквизитами верхнего уровня, созданными в конфигураторе (например, Артикул, Код, Наименование).В типовых конфигурациях 1С (УТ 11, ERP, КА, БП 3.0 и др.) механизмы БСП (Библиотеки Стандартных Подсистем) разделяют дополнительные свойства на два типа:
ДополнительныеРеквизиты справочника Номенклатура). Они изменяются вместе с объектом и отображаются на его форме.ЗначенияСвойствОбъектов.Посмотрим на структуру табличной части ДополнительныеРеквизиты справочника Номенклатура. В ней содержатся следующие основные колонки:
– Свойство — ссылка на план видов характеристик ДополнительныеРеквизитыИСведения;
– Значение — значение реквизита (составной тип данных).
Проанализируем ситуацию: чтобы найти элемент номенклатуры по значению дополнительного реквизита, необходимо обратиться к табличной части Справочник.Номенклатура.ДополнительныеРеквизиты с помощью запроса.
Рассмотрим частую ошибку разработчиков при написании запроса. Не рекомендуется выбирать данные через вложенную таблицу реквизитов объекта в секции ВЫБРАТЬ (например, Номенклатура.ДополнительныеРеквизиты.(...)), так как это приводит к неоптимальной выборке. Правильный подход — обращаться напрямую к табличной части справочника.
Рассмотрим пример правильного кода для поиска ссылки на номенклатуру:
// 1. Получаем ссылку на сам дополнительный реквизит (свойство)
СвойствоСтарыйКод = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("СтарыйКод");
Если Не ЗначениеЗаполнено(СвойствоСтарыйКод) Тогда
ВызватьИсключение "Не найдено свойство 'СтарыйКод'!";
КонецЕсли;
// 2. Формируем запрос к табличной части справочника
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| НоменклатураДоп.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДоп
|ГДЕ
| НоменклатураДоп.Свойство = &Свойство
| И НоменклатураДоп.Значение = &Значение
| И НЕ НоменклатураДоп.Ссылка.ЭтоГруппа";
Запрос.УстановитьПараметр("Свойство", СвойствоСтарыйКод);
Запрос.УстановитьПараметр("Значение", Число(ИскомыйКод)); // Убедитесь в соответствии типа данных
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Работаем со найденной ссылкой
СсылкаНаНоменклатуру = Выборка.Номенклатура;
КонецЦикла;
Если в вашей конфигурации свойство заведено не как дополнительный реквизит, а как дополнительное сведение, данные хранятся в регистре сведений. В этом случае поиск выполняем по регистру ЗначенияСвойствОбъектов.
Разберем по шагам соответствующий запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗначенияСвойств.Объект КАК Номенклатура
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойств
|ГДЕ
| ЗначенияСвойств.Свойство = &Свойство
| И ЗначенияСвойств.Значение = &Значение";
Запрос.УстановитьПараметр("Свойство", СвойствоСтарыйКод);
Запрос.УстановитьПараметр("Значение", ИскомыйКод);
РезультатЗапроса = Запрос.Выполнить();
Значение имеет составной тип. Если реквизит числовой, передавайте в параметр &Значение строго тип Число. Если значение выбирается из списка предустановленных значений, в параметр нужно передавать ссылку на элемент справочника ЗначенияСвойствОбъектов.НайтиПоНаименованию() для PVI может быть ненадёжным, если в базе есть свойства с одинаковыми именами для разных наборов. В реальных задачах предпочтительно искать свойство по правильному набору или уникальному имени.ВЫБРАТЬ РАЗЛИЧНЫЕ при запросе к табличным частям, чтобы исключить повторяющиеся ссылки в результатах выборки.