Часто при разработке на платформе 1С возникает задача найти элемент справочника по его наименованию, ограничив при этом область поиска конкретной группой (папкой). Рассмотрим ситуацию, когда разработчик пытается использовать стандартный метод поиска, но система не находит нужный элемент. Проанализируем типичный пример кода:
Род = Справочники.Номенклатура.НайтиПоКоду(5891);
Лом = Справочники.Номенклатура.НайтиПоНаименованию(СтрШихта,,Род);
Разберем по шагам, почему такой подход может не сработать и какие скрытые подводные камни здесь присутствуют.
Выясним, что может пойти не так при использовании методов НайтиПоКоду и НайтиПоНаименованию:
5891 может привести к тому, что переменная Род останется пустой. Правильнее искать по строке с учетом лидирующих нулей (если они есть), например: "00000005891". Всегда проверяйте, найдена ли родительская папка, прежде чем передавать ее параметром в следующий поиск.НайтиПоНаименованию, когда ему передается параметр родителя, осуществляет поиск элемента исключительно в корне указанной группы. Если искомая номенклатура лежит в подпапке, которая находится внутри папки Род, платформенный метод ее не увидит.СтрШихта,,Род), который отвечает за точное соответствие. По умолчанию он принимает значение Истина. Это значит, что если в переменной СтрШихта случайно затесался пробел в начале, в конце или между словами стоит два пробела, поиск вернет пустую ссылку.Посмотрим на частую ошибку, когда разработчики пытаются заменить поиск по наименованию на поиск по реквизиту:
// Такой код вызовет ошибку времени выполнения!
Справочник.Номенклатура.НайтиПоРеквизиту("Наименование", СтрШихта, Род);
Проанализируем причину ошибки. Дело в том, что метод НайтиПоРеквизиту предназначен только для пользовательских реквизитов, которые разработчик сам добавил в дерево метаданных. "Код" и "Наименование" являются стандартными реквизитами платформы, поэтому применение к ним данного метода недопустимо.
Рассмотрим, как надежно и правильно решить задачу поиска элемента в пределах группы.
Решение 1: Использование запроса с условием В ИЕРАРХИИ
Если элемент может находиться в любой вложенной папке внутри родителя, необходимо использовать запрос. Это не только решает проблему глубины поиска, но и работает значительно быстрее, особенно если поиск происходит в цикле.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование = &Наименование
| И Номенклатура.Родитель В ИЕРАРХИИ(&Родитель)";
Запрос.УстановитьПараметр("Наименование", СтрШихта);
Запрос.УстановитьПараметр("Родитель", Род);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
НайденнаяСсылка = Выборка.Ссылка;
КонецЕсли;
Решение 2: Поиск по части наименования
Если наименование может незначительно отличаться или содержать лишние пробелы, запрос позволяет использовать оператор ПОДОБНО. Это невозможно реализовать стандартными объектными методами.
// Фрагмент текста запроса:
// ГДЕ Номенклатура.Наименование ПОДОБНО &Наименование
// Установка параметра:
Запрос.УстановитьПараметр("Наименование", "%" + СтрШихта + "%");
Решение 3: Отказ от поиска по наименованию
Искать элементы по наименованию в принципе считается плохой практикой ("вредно для здоровья" кода). Пользователи могут в любой момент изменить название элемента, и ваш код перестанет работать. Разберем более надежные альтернативы:
Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор("...")).Справочники.Номенклатура.Шихта).