Как правильно найти запись в справочнике 1С:Предприятие 7.7 и избежать ошибки «Не выбран элемент!»

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

Работа со справочниками — одна из самых частых задач при разработке в среде 1С:Предприятие 7.7. Однако начинающие разработчики часто сталкиваются с ситуацией, когда код кажется логичным, но программа выдает ошибку «Не выбран элемент!» или попросту не находит существующую запись. Разберем детально, почему это происходит и как правильно организовать поиск.

Анализ основной ошибки: почему поиск в цикле не работает

Рассмотрим ситуацию, с которой столкнулся автор темы. В его коде была предпринята попытка совместить перебор элементов справочника и метод прямого поиска:


Процедура Сформировать()
    Сотр = СоздатьОбъект("Справочник.Сотрудники");
    Сотр.ВыбратьЭлементы();
    
    Пока Сотр.ПолучитьЭлемент() = 1 Цикл
        // ОШИБКА ЗДЕСЬ:
        Если Сотр.НайтиПоНаименованию(СокрЛП(С000), 0, 0) = 1 Тогда
            Предупреждение("Найден");
        Иначе
            Предупреждение("Нет!!!");
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Проанализируем причину сбоя. В 1С 7.7 объект типа Справочник ведет себя как единый контейнер с внутренним указателем. Когда мы вызываем метод ВыбратьЭлементы(), система подготавливает выборку. Метод ПолучитьЭлемент() последовательно перемещает указатель по этой выборке.

Важное правило: Любой метод прямого поиска, такой как НайтиПоНаименованию, НайтиПоКоду или НайтиПоРеквизиту, немедленно сбивает текущую выборку. Как только вызывается поиск, 1С переключает объект справочника в режим поиска конкретного элемента, и «память» о том, на каком шаге находился цикл Пока, теряется. Следующий вызов ПолучитьЭлемент() приводит к ошибке «Не выбран элемент!», так как выборка была аннулирована поисковой операцией.

Решение №1: Прямой поиск (оптимальный вариант)

Если нам нужно найти один конкретный элемент по его названию, нам совершенно не нужен цикл. Мы просто создаем объект и сразу вызываем метод поиска. Это работает максимально быстро, так как система использует индексы базы данных.

Рассмотрим правильный код для поиска сотрудника по значению реквизита формы С000:


Процедура Сформировать()
    Перем ТекСотр;
    ТекСотр = СоздатьОбъект("Справочник.Сотрудники");
    
    // Ищем во всем справочнике (второй параметр 0 - без учета иерархии)
    // Третий параметр 0 - полное совпадение наименования
    Если ТекСотр.НайтиПоНаименованию(СокрЛП(С000), 0, 0) = 1 Тогда
        Предупреждение("Сотрудник " + ТекСотр.Наименование + " успешно найден!");
        // Теперь объект ТекСотр позиционирован на найденном элементе
        // Мы можем получить его данные или передать куда-либо через ТекСотр.ТекущийЭлемент()
    Иначе
        Предупреждение("Сотрудник с наименованием '" + С000 + "' не найден.");
    КонецЕсли;
КонецПроцедуры

Решение №2: Поиск через ручной перебор (в цикле)

Иногда возникают задачи, когда прямой поиск не подходит (например, нужно найти элемент по части строки или по сложному условию, не используя встроенный индекс). в этом случае мы используем цикл, но не используем внутри него методы Найти.... Вместо этого мы сравниваем значения реквизитов напрямую.

Проанализируем, как это реализовать правильно:


Процедура Сформировать()
    Сотр = СоздатьОбъект("Справочник.Сотрудники");
    ИскомоеИмя = СокрЛП(С000);
    ФлагНайдено = 0;
    
    Сотр.ВыбратьЭлементы();
    Пока Сотр.ПолучитьЭлемент() = 1 Цикл
        // Проверяем условие без вызова методов поиска
        Если СокрЛП(Сотр.Наименование) = ИскомоеИмя Тогда
            Предупреждение("Элемент найден: " + Сотр.ТекущийЭлемент());
            ФлагНайдено = 1;
            Прервать; // Выходим из цикла, если результат найден
        КонецЕсли;
    КонецЦикла;
    
    Если ФлагНайдено = 0 Тогда
        Предупреждение("Ничего не найдено.");
    КонецЕсли;
КонецПроцедуры

Важные нюансы метода НайтиПоНаименованию

При использовании НайтиПоНаименованию(Наименование, Режим, КраткоеСоответствие) следует помнить о параметрах:

  1. Режим: 0 — поиск по всему справочнику; 1 — поиск только внутри текущего родителя (если справочник иерархический).
  2. КраткоеСоответствие: 0 — искать точное совпадение; 1 — искать по первым символам (префиксный поиск). Если вы ищете «Иванов», а в базе есть «Иванов Иван», при значении 1 система найдет первого подходящего.

Также обратим внимание на проблему разных раскладок клавиатуры. Это одна из самых частых причин, почему визуально одинаковые строки не находятся. Буква «С» в русском языке и «C» в английском имеют разные коды. При вводе данных в справочник или в поле поиска пользователь мог ошибиться раскладкой. Для решения таких проблем часто используют функции нормализации строк.

Работа с найденным элементом

Когда поиск завершился успешно (метод вернул 1), объект справочника «позиционируется» на найденной записи. Чтобы использовать эту запись в дальнейшем (например, записать в реквизит документа), нужно использовать метод ТекущийЭлемент().

Рассмотрим пример:


Если Спр.НайтиПоНаименованию("Петров", 0, 0) = 1 Тогда
    ВыбранныйСотрудник = Спр.ТекущийЭлемент();
    // Теперь переменная ВыбранныйСотрудник содержит ссылку на элемент
КонецЕсли;

Если просто написать ВыбранныйСотрудник = Спр, вы получите ссылку на сам программный объект-контейнер, что может привести к непредсказуемым ошибкам при записи в базу данных.

Дополнительные способы поиска в 1С 7.7

Помимо поиска по наименованию, существуют и другие эффективные методы, которые мы можем рассмотреть:

  1. НайтиПоКоду(Код, Режим): Самый быстрый способ, если известны уникальные коды элементов. Работает аналогично поиску по наименованию.
  2. НайтиПоРеквизиту(ИмяРеквизита, Значение, Режим): Позволяет искать по произвольному полю (например, по ИНН или Табельному номеру). Важно: этот метод будет работать только в том случае, если в Конфигураторе у данного реквизита установлен флаг «Сортировка» или «Отбор по реквизиту». Без индекса этот метод работать не будет.

Подводя итог, можно сказать, что для эффективной работы в 1С 7.7 необходимо четко разделять задачи массовой обработки (используем ВыбратьЭлементы и цикл) и задачи точечного поиска (используем методы Найти... без циклов). Соблюдение этого правила избавит ваш код от ошибок позиционирования и значительно ускорит работу программы.

← На главную