Как проверить наличие предопределенного элемента справочника в 1С и избежать критической ошибки?

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

При разработке на платформе 1С:Предприятие часто возникает необходимость динамически обратиться к предопределенному элементу справочника по его имени. Стандартный и самый очевидный путь — использовать конструкцию Справочники.ИмяСправочника[ИмяЭлемента]. Однако этот подход таит в себе серьезную опасность. Если предопределенного элемента с таким именем не существует в метаданных или он отсутствует в самой базе данных, система незамедлительно вызовет исключение и аварийно завершит выполнение кода.

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

В чем кроется причина ошибки?

Для начала разберем природу механизма предопределенных данных в 1С. Предопределенный элемент существует в двух ипостасях:

  1. В метаданных конфигурации: разработчик описывает имя элемента в конфигураторе.
  2. В таблице базы данных (ИБ): физическая запись, которая создается платформой при первом запуске или обновлении информационной базы.

Критическая ошибка (например, «Предопределенный элемент отсутствует в данных») может возникнуть в двух сценариях. Во-первых, если имени элемента в принципе нет в структуре метаданных конфигурации. Во-вторых, если в метаданных элемент описан, но физически в таблице базы данных он еще не создан (например, отключено автоматическое обновление предопределенных данных) или связь между метаданными и записью ИБ была нарушена программным путем.

Рассмотрим по шагам все возможные варианты решения этой задачи — от простых обходных путей до профессиональных стандартов разработки.

Решение 1. Проверка через метаданные конфигурации

Если нам необходимо выяснить, задано ли в принципе такое имя предопределенного элемента на уровне конфигуратора, мы можем обратиться к коллекции метаданных. Метод менеджера справочника ПолучитьИменаПредопределенных() возвращает массив строк, содержащих имена всех предопределенных элементов.

Проанализируем пример кода, реализующий этот подход:


ИмяИскомогоЭлемента = "ВажныйКлиент";
ИменаПредопределенных = Метаданные.Справочники.Клиенты.ПолучитьИменаПредопределенных();

Если ИменаПредопределенных.Найти(ИмяИскомогоЭлемента) <> Неопределено Тогда
    // Имя предопределенного элемента существует в конфигурации.
    // Теперь можно безопасно обращаться к нему.
    ЭлементСсылка = Справочники.Клиенты[ИмяИскомогоЭлемента];
Иначе
    // Такого элемента в метаданных нет, обрабатываем альтернативный сценарий.
    ЭлементСсылка = Справочники.Клиенты.ПустаяСсылка();
КонецЕсли;

Важное предупреждение: этот способ проверяет наличие элемента только в конфигураторе. Если в пользовательской базе данных этот элемент был физически удален, отвязан (очищено поле ИмяПредопределенныхДанных) или база данных не обновилась должным образом, обращение Справочники.Клиенты[ИмяИскомогоЭлемента] все равно вызовет ошибку выполнения. Поэтому использовать данный метод в чистом виде рекомендуется только тогда, когда вы абсолютно уверены в целостности базы данных.

Решение 2. Безопасный запрос к базе данных

Чтобы гарантировать физическое существование элемента непосредственно в таблицах информационной базы, лучшим решением является использование запроса. Многие разработчики допускают ошибку, пытаясь передать конструкцию вида ЗНАЧЕНИЕ(Справочник.Имя.Элемент) в запрос, что опять же приводит к падению системы, если элемента нет.

Правильный подход заключается в поиске элемента по текстовому представлению его имени через стандартный реквизит ИмяПредопределенныхДанных. Разберем этот пример подробнее:


Функция НайтиПредопределенныйЭлементБезопасно(ИмяЭлемента) Экспорт
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	Клиенты.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.Клиенты КАК Клиенты
        |ГДЕ
        |	Клиенты.ИмяПредопределенныхДанных = &ИмяЭлемента";
    
    Запрос.УстановитьПараметр("ИмяЭлемента", ИмяЭлемента);
    РезультатЗапроса = Запрос.Выполнить();
    
    Если РезультатЗапроса.Пустой() Тогда
        Возврат Справочники.Клиенты.ПустаяСсылка();
    Иначе
        Выборка = РезультатЗапроса.Выбрать();
        Выборка.Следующий();
        Возврат Выборка.Ссылка;
    КонецЕсли;
КонецФункции

Этот способ является максимально надежным. Запрос никогда не упадет в ошибку, даже если переданного имени нет в метаданных или в базе данных. Он просто вернет пустой результат, который мы легко и безопасно обработаем в коде.

Решение 3. Использование стандартных функций БСП

Если вы ведете разработку в современной типовой конфигурации (такой как 1С:ERP, Комплексная автоматизация, Управление торговлей или Бухгалтерия предприятия), вам не нужно изобретать велосипед. В составе Библиотеки стандартных подсистем (БСП) есть готовые механизмы для решения этой задачи.

Методисты 1С реализовали специальную функцию в общем модуле ОбщегоНазначения, которая берет на себя все проверки и кэширование результатов для оптимизации производительности.

Посмотрим на пример использования функций БСП на сервере:


ИмяПолное = "Справочник.Клиенты.ВажныйКлиент";
СсылкаНаЭлемент = ОбщегоНазначения.ПредопределенныйЭлемент(ИмяПолное);

Если ЗначениеЗаполнено(СсылкаНаЭлемент) Тогда
    // Элемент успешно найден в базе данных, работаем с ним
Иначе
    // Элемента не существует в ИБ или метаданных, ошибка не вызывается
КонецЕсли;

Для работы на стороне клиента (например, в тонком клиенте, где менеджеры справочников недоступны) в БСП предусмотрен аналогичный клиентский аналог:


СсылкаНаЭлемент = ОбщегоНазначенияКлиент.ПредопределенныйЭлемент("Справочник.Клиенты.ВажныйКлиент");

Использование БСП — это индустриальный стандарт разработки под 1С. Данные методы возвращают Неопределено или пустую ссылку вместо генерации исключения, что делает код чистым, понятным и отказоустойчивым.

Решение 4. Трюк с заполнением свойств структуры

Рассмотрим один весьма элегантный и быстрый «хак», который позволяет выполнить быструю проверку на сервере без обращения к метаданным и без написания громоздких запросов. Этот способ основан на поведении платформенного метода ЗаполнитьЗначенияСвойств().

Суть метода заключается в том, что менеджер справочника ведет себя как объект, содержащий свойства, совпадающие с именами предопределенных элементов. Если мы попытаемся скопировать эти свойства в структуру, то скопируются только реально существующие элементы.

Выполним проверку по следующему алгоритму:


// Создаем структуру-затычку с произвольным проверочным значением (например, число 1)
ПроверяемаяСтруктура = Новый Структура(ИмяИскомогоЭлемента, 1);

// Пробуем заполнить структуру свойствами из менеджера справочника
ЗаполнитьЗначенияСвойств(ПроверяемаяСтруктура, Справочники.Клиенты);

// Анализируем результат заполнения
Если ПроверяемаяСтруктура[ИмяИскомогоЭлемента] = 1 Тогда
    // Значение не изменилось, значит свойства с таким именем в менеджере нет
    ВызватьИсключение "Предопределенный элемент не существует!";
Иначе
    // Значение перезаписалось ссылкой на предопределенный элемент
    СсылкаНаЭлемент = ПроверяемаяСтруктура[ИмяИскомогоЭлемента];
КонецЕсли;

Этот метод работает чрезвычайно быстро и не требует выполнения SQL-запросов, однако он также опирается на менеджер справочника, а значит, проверяет только наличие имени в метаданных конфигурации, но не гарантирует физическое присутствие записи в базе данных.

Резюме и рекомендации

Подводя итог нашему анализу, дадим несколько практических рекомендаций по выбору оптимального метода:

← На главную