Как правильно организовать поиск элементов справочников в коде 1С и почему поиск по коду — это плохая практика

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

В процессе разработки на платформе 1С:Предприятие 8 каждый программист рано или поздно сталкивается с необходимостью обратиться к конкретному элементу справочника. Например, нам нужно программно подставить «Основной склад» в документ или выбрать специфический тип номенклатуры для расчетов. Самый простой и очевидный путь — использовать метод НайтиПоКоду(). Однако, как справедливо замечают опытные разработчики, этот путь ведет к хрупкости системы. Давайте разберем, почему «жесткое» кодирование строковых кодов в конфигурации считается «плохим тоном», и какие архитектурно верные альтернативы мы можем применить в своей работе.

Почему поиск по коду и наименованию — это рискованно

Прежде чем мы перейдем к решениям, проанализируем ситуацию и выясним причины, по которым поиск по коду (или, что еще хуже, по наименованию) может привести к ошибкам:

  1. Человеческий фактор: Пользователь может случайно или намеренно изменить код элемента в режиме «1С:Предприятие». Как только код «00001» превратится в «00-001», программный код перестанет находить элемент, и логика приложения сломается.
  2. Проблемы с RLS: При использовании механизма ограничения прав доступа на уровне записей (RLS), попытка поиска элемента без использования привилегированного режима может вызвать ошибку или вернуть «ПустуюСсылку», если у пользователя нет прав на этот конкретный объект.
  3. Непереносимость данных: При переносе кода между разными базами (например, из тестовой в рабочую) коды элементов могут не совпадать, что потребует постоянной правки модулей.

Рассмотрим подробнее современные и надежные способы хранения ссылок на нужные нам элементы.

Способ 1. Предопределенные элементы (современный подход)

В версии платформы 8.3 механизмы работы с предопределенными данными были значительно расширены. Если раньше мы создавали предопределенные элементы только в Конфигураторе, то теперь мы можем программно связывать существующие элементы базы данных с именами предопределенных данных.

Разберем, как это работает. Мы можем использовать метод УстановитьИмяПредопределенныхДанных(), чтобы превратить обычный элемент, созданный пользователем, в «псевдо-предопределенный». Это позволяет нам обращаться к нему в коде максимально лаконично:


// Обращение к элементу как к свойству справочника
СкладОбъект = Справочники.Склады.ОсновнойСклад;

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


ЭлементСправочника = Справочники.Склады.НайтиПоКоду("УТ-00001");
ОбъектСклада = ЭлементСправочника.ПолучитьОбъект();
ОбъектСклада.ИмяПредопределенныхДанных = "ОсновнойСклад";
ОбъектСклада.Записать();

Способ 2. Использование регистров сведений для хранения настроек

Часто бывает так, что элементов много, и они могут меняться в зависимости от организации или пользователя. В этом случае мы создаем специальный Регистр сведений (например, «НастройкиПоУмолчанию» или «СистемныеНастройки»).

Проанализируем структуру такого регистра:

Теперь создадим в общем модуле функцию-обертку, которая будет возвращать нам нужное значение. Чтобы не нагружать базу данных постоянными запросами, обязательно установим у модуля свойство «Повторное использование возвращаемых значений».


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

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

Способ 3. Функциональные опции

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


// Получаем значение функциональной опции
Склад = ПолучитьФункциональнуюОпцию("ОсновнойСкладОрганизации");

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

Способ 4. Добавление строкового реквизита «Идентификатор»

Если нам нужно решение «дешево и сердито», но надежнее, чем поиск по коду, мы можем добавить в справочник дополнительный реквизит ИдентификаторДляРазработчика (строка, индексировать). В этом поле мы записываем понятное имя, например, «ГЛАВНЫЙ_ОФИС».

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


// Пример поиска по системному идентификатору
Ссылка = Справочники.Склады.НайтиПоРеквизиту("ИдентификаторДляРазработчика", "ГЛАВНЫЙ_ОФИС");
Если Ссылка.Пустая() Тогда
    // Обработка ситуации, если элемент не найден
КонецЕсли;

Способ 5. Использование констант

Для одиночных, глобальных настроек (например, «Валюта регламентированного учета» или «Организация по умолчанию») идеально подходят Константы. Обращение к ним максимально быстрое, а платформа предоставляет удобные формы для их заполнения.


// Чтение константы
НашаОрганизация = Константы.ОсновнаяОрганизация.Получить();

Рекомендации по оптимизации: Кэширование и «Соответствие»

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

  1. До начала цикла выгрузите все пары «Идентификатор — Ссылка» в объект Соответствие (Map).
  2. Внутри цикла обращайтесь к этому объекту в оперативной памяти.

// Оптимизированный поиск через Соответствие
ТаблицаСопоставления = Новый Соответствие;
Выборка = Справочники.Склады.Выбрать();
Пока Выборка.Следующий() Цикл
    ТаблицаСопоставления.Вставить(Выборка.ИдентификаторДляРазработчика, Выборка.Ссылка);
КонецЦикла;

// В цикле обработки данных
ТекущаяСсылка = ТаблицаСопоставления.Получить("НУЖНЫЙ_СКЛАД");

Подведем итог. Использование НайтиПоКоду() допустимо только в разовых внешних обработках или в ситуациях, когда вы на 100% уверены в неизменности структуры данных (например, в жестко регламентированных классификаторах). Для разработки тиражных решений или сложных корпоративных систем всегда выбирайте между предопределенными элементами, регистрами настроек или функциональными опциями. Это сделает ваш код надежным, читаемым и легким в сопровождении.

← На главную