Работа со справочниками — одна из самых частых задач при разработке в среде 1С:Предприятие 7.7. Однако начинающие разработчики часто сталкиваются с ситуацией, когда код кажется логичным, но программа выдает ошибку «Не выбран элемент!» или попросту не находит существующую запись. Разберем детально, почему это происходит и как правильно организовать поиск.
Рассмотрим ситуацию, с которой столкнулся автор темы. В его коде была предпринята попытка совместить перебор элементов справочника и метод прямого поиска:
Процедура Сформировать()
Сотр = СоздатьОбъект("Справочник.Сотрудники");
Сотр.ВыбратьЭлементы();
Пока Сотр.ПолучитьЭлемент() = 1 Цикл
// ОШИБКА ЗДЕСЬ:
Если Сотр.НайтиПоНаименованию(СокрЛП(С000), 0, 0) = 1 Тогда
Предупреждение("Найден");
Иначе
Предупреждение("Нет!!!");
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем причину сбоя. В 1С 7.7 объект типа Справочник ведет себя как единый контейнер с внутренним указателем. Когда мы вызываем метод ВыбратьЭлементы(), система подготавливает выборку. Метод ПолучитьЭлемент() последовательно перемещает указатель по этой выборке.
Важное правило: Любой метод прямого поиска, такой как НайтиПоНаименованию, НайтиПоКоду или НайтиПоРеквизиту, немедленно сбивает текущую выборку. Как только вызывается поиск, 1С переключает объект справочника в режим поиска конкретного элемента, и «память» о том, на каком шаге находился цикл Пока, теряется. Следующий вызов ПолучитьЭлемент() приводит к ошибке «Не выбран элемент!», так как выборка была аннулирована поисковой операцией.
Если нам нужно найти один конкретный элемент по его названию, нам совершенно не нужен цикл. Мы просто создаем объект и сразу вызываем метод поиска. Это работает максимально быстро, так как система использует индексы базы данных.
Рассмотрим правильный код для поиска сотрудника по значению реквизита формы С000:
Процедура Сформировать()
Перем ТекСотр;
ТекСотр = СоздатьОбъект("Справочник.Сотрудники");
// Ищем во всем справочнике (второй параметр 0 - без учета иерархии)
// Третий параметр 0 - полное совпадение наименования
Если ТекСотр.НайтиПоНаименованию(СокрЛП(С000), 0, 0) = 1 Тогда
Предупреждение("Сотрудник " + ТекСотр.Наименование + " успешно найден!");
// Теперь объект ТекСотр позиционирован на найденном элементе
// Мы можем получить его данные или передать куда-либо через ТекСотр.ТекущийЭлемент()
Иначе
Предупреждение("Сотрудник с наименованием '" + С000 + "' не найден.");
КонецЕсли;
КонецПроцедуры
Иногда возникают задачи, когда прямой поиск не подходит (например, нужно найти элемент по части строки или по сложному условию, не используя встроенный индекс). в этом случае мы используем цикл, но не используем внутри него методы Найти.... Вместо этого мы сравниваем значения реквизитов напрямую.
Проанализируем, как это реализовать правильно:
Процедура Сформировать()
Сотр = СоздатьОбъект("Справочник.Сотрудники");
ИскомоеИмя = СокрЛП(С000);
ФлагНайдено = 0;
Сотр.ВыбратьЭлементы();
Пока Сотр.ПолучитьЭлемент() = 1 Цикл
// Проверяем условие без вызова методов поиска
Если СокрЛП(Сотр.Наименование) = ИскомоеИмя Тогда
Предупреждение("Элемент найден: " + Сотр.ТекущийЭлемент());
ФлагНайдено = 1;
Прервать; // Выходим из цикла, если результат найден
КонецЕсли;
КонецЦикла;
Если ФлагНайдено = 0 Тогда
Предупреждение("Ничего не найдено.");
КонецЕсли;
КонецПроцедуры
При использовании НайтиПоНаименованию(Наименование, Режим, КраткоеСоответствие) следует помнить о параметрах:
0 — поиск по всему справочнику; 1 — поиск только внутри текущего родителя (если справочник иерархический).0 — искать точное совпадение; 1 — искать по первым символам (префиксный поиск). Если вы ищете «Иванов», а в базе есть «Иванов Иван», при значении 1 система найдет первого подходящего.Также обратим внимание на проблему разных раскладок клавиатуры. Это одна из самых частых причин, почему визуально одинаковые строки не находятся. Буква «С» в русском языке и «C» в английском имеют разные коды. При вводе данных в справочник или в поле поиска пользователь мог ошибиться раскладкой. Для решения таких проблем часто используют функции нормализации строк.
Когда поиск завершился успешно (метод вернул 1), объект справочника «позиционируется» на найденной записи. Чтобы использовать эту запись в дальнейшем (например, записать в реквизит документа), нужно использовать метод ТекущийЭлемент().
Рассмотрим пример:
Если Спр.НайтиПоНаименованию("Петров", 0, 0) = 1 Тогда
ВыбранныйСотрудник = Спр.ТекущийЭлемент();
// Теперь переменная ВыбранныйСотрудник содержит ссылку на элемент
КонецЕсли;
Если просто написать ВыбранныйСотрудник = Спр, вы получите ссылку на сам программный объект-контейнер, что может привести к непредсказуемым ошибкам при записи в базу данных.
Помимо поиска по наименованию, существуют и другие эффективные методы, которые мы можем рассмотреть:
Подводя итог, можно сказать, что для эффективной работы в 1С 7.7 необходимо четко разделять задачи массовой обработки (используем ВыбратьЭлементы и цикл) и задачи точечного поиска (используем методы Найти... без циклов). Соблюдение этого правила избавит ваш код от ошибок позиционирования и значительно ускорит работу программы.