Как реализовать поиск в перечислениях по имени элемента, если объект не найден в справочниках?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С часто возникают задачи, когда необходимо обработать параметры запроса или данные обмена динамически. Особенно это актуально, когда типы данных заранее не определены жестко, а формируются на лету из строковых представлений. В данной статье мы разберем, как корректно организовать поиск по «теневым» или динамическим объектам, переключаясь между справочниками и перечислениями.

Постановка задачи и анализ исходной ситуации

Рассмотрим ситуацию: у нас есть список параметров, где тип объекта зашит в строку (например, через префикс теневая). Нам нужно получить ссылку на объект. Если это справочник, мы ищем по наименованию. Если это перечисление — по внутреннему имени (идентификатору) значения. Основная сложность заключается в том, что прямое обращение к коллекции Перечисления по несуществующему имени приведет к аварийному завершению работы программы.

Проанализируем базовый алгоритм, который поможет нам безопасно определять тип объекта и извлекать данные.

Решение 1: Использование коллекции Метаданные для проверки существования

Самый надежный способ проверить, к какой категории относится объект (справочник или перечисление) — это обратиться к коллекции Метаданные (или использовать информер по метаданным). Разберем по шагам, как это реализовать в коде.


// Формируем имя объекта для поиска в метаданных
имяОбъекта = "теневая" + НРег(СтрЗаменить(Параметр.ТипПараметра, " ", ""));

// 1. Проверяем, существует ли такой справочник
Если НЕ Метаданные.Справочники.Найти(имяОбъекта) = Неопределено Тогда
    // Если справочник найден, используем стандартный метод поиска по наименованию
    ЗначениеПараметра = Справочники[имяОбъекта].НайтиПоНаименованию(Параметр.ЗначениеПараметра, Истина);
    
// 2. Если справочник не найден, проверяем коллекцию перечислений
ИначеЕсли НЕ Метаданные.Перечисления.Найти(имяОбъекта) = Неопределено Тогда
    
    // Внутри перечисления нужно также проверить наличие конкретного значения по имени
    ОбъектМетаданныхПеречисление = Метаданные.Перечисления.Найти(имяОбъекта);
    Если НЕ ОбъектМетаданныхПеречисление.ЗначенияПеречисления.Найти(Параметр.ЗначениеПараметра) = Неопределено Тогда
        // Если значение существует, получаем ссылку через менеджер перечисления
        ЗначениеПараметра = Перечисления[имяОбъекта][Параметр.ЗначениеПараметра];
    Иначе
        ЗначениеПараметра = Неопределено;
    КонецЕсли;
    
КонецЕсли;

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

Решение 2: Использование функции Тип() для упрощения логики

Вместо перебора коллекций метаданных, мы можем воспользоваться системной функцией Тип(). Если сконструированная строка типа верна, функция вернет объект типа Тип, в противном случае — Неопределено. Посмотрим, как это выглядит на практике:


имяОбъекта = "теневая" + НРег(СтрЗаменить(Параметр.ТипПараметра, " ", ""));

// Пытаемся определить, справочник это или перечисление через системные типы
ТипСправочника = Тип("СправочникСсылка." + имяОбъекта);
ТипПеречисления = Тип("ПеречислениеСсылка." + имяОбъекта);

Если ТипСправочника <> Тип("Неопределено") Тогда
    ЗначениеПараметра = Справочники[имяОбъекта].НайтиПоНаименованию(Параметр.ЗначениеПараметра, Истина);
ИначеЕсли ТипПеречисления <> Тип("Неопределено") Тогда
    Попытка
        ЗначениеПараметра = Перечисления[имяОбъекта][Параметр.ЗначениеПараметра];
    Исключение
        ЗначениеПараметра = Неопределено; // Значение в перечислении не найдено
    КонецПопытки;
КонецЕсли;

Этот метод считается более элегантным и коротким. Однако стоит помнить, что конструкция Попытка...Исключение внутри цикла может незначительно снизить производительность, если исключения будут возникать слишком часто.

Важные нюансы при работе с перечислениями

Проанализируем важные технические моменты, которые часто упускают разработчики, выполняя поиск ссылок на справочник, перечисление или другие объекты:

  1. Различие между Именем и Синонимом: Обращение Перечисления[имяОбъекта][ИмяЗначения] работает только с Именем (идентификатором), заданным в конфигураторе. Если в параметре ЗначениеПараметра передается пользовательский синоним (например, "НДС 20%" вместо "НДС20"), такой поиск вернет ошибку или Неопределено. Для поиска по синониму придется перебирать все значения перечисления в цикле и сравнивать их строковое представление.
  2. Точность поиска в справочниках: Метод НайтиПоНаименованию без указания второго параметра выполняет поиск по началу строки. Если вы ищете товар "Гвоздь", а в базе есть "Гвоздь стальной", система может вернуть не то, что вы ожидали. Всегда используйте точный поиск, при необходимости задействуя получение даты создания объекта для верификации.
  3. Производительность метаданных: Если список параметров содержит тысячи элементов, постоянное обращение к Метаданные.Справочники.Найти() может замедлить работу. В этом случае рекомендуем один раз перед циклом создать Соответствие, в которое поместить имена всех нужных объектов, и проверять наличие имени уже в этом «кэше» в оперативной памяти.

Альтернативный метод: Получение значения через XML

Выясним причину, почему иногда выгодно использовать сериализацию. Существует «хитрый» способ получить ссылку на любое перечисление или справочник, если у нас есть строковое имя типа и строковый идентификатор. Это делается через механизмы XML или JSON преобразования.


// Пример логики для перечисления через XMLТип (схематично)
СтрокаXML = "<Value>EnumRef." + имяОбъекта + "." + Параметр.ЗначениеПараметра + "</Value>";
// Далее используется десериализация через СредстваXML или аналогичные механизмы.

Хотя этот метод технически сложнее в реализации и «тяжелее» для процессора, он позволяет написать универсальный код, который не содержит условий Если Справочник ... ИначеЕсли Перечисление.

Заключение

Мы рассмотрели несколько подходов к решению задачи динамического поиска. Проанализировав ситуацию, можно сделать вывод: наиболее сбалансированным решением является проверка через метаданные (Решение 1). Она обеспечивает максимальную безопасность кода и наглядность для других разработчиков, которые будут поддерживать вашу систему. Не забывайте про разницу между именами и синонимами, а также всегда учитывайте возможность дублирования имен в разных коллекциях метаданных.

← На главную