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

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

В процессе разработки на платформе 1С часто возникает задача обратиться к конкретному, заранее известному элементу справочника. Классический пример — использование определенной валюты, типа цен или статьи затрат в алгоритмах. Начинающие разработчики часто решают эту задачу "в лоб", используя поиск по коду или наименованию. Однако такой подход крайне ненадежен и может привести к ошибкам в самый неподходящий момент. Давайте разберемся, почему так происходит и какие существуют правильные и надежные способы решения этой задачи.

Почему поиск по коду и наименованию — плохая практика?

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

Аналогичная ситуация с поиском по коду через НайтиПоКоду(). Кажется, что код — это нечто статичное, но на практике это не так. Проанализируем основные причины, по которым этот метод также ненадежен:

  1. Изменение пользователем. Если у пользователя есть права, он может изменить код элемента так же легко, как и наименование.
  2. Отсутствие кода как такового. Во многих типовых конфигурациях (например, в УТ или ERP) у некоторых справочников длина кода установлена в 0. Это значит, что код для элементов этого справочника просто не используется.
  3. Неуникальные коды. При обмене данными или после обновления конфигурации могут возникать ситуации, когда в базе появляются элементы с одинаковыми кодами, что приведет к непредсказуемому результату поиска.
  4. Разные коды в разных базах. Если вы создаете новую информационную базу на основе той же конфигурации и пользователи начинают вводить данные вручную, те же самые по смыслу элементы получат совершенно другие, автоматически присвоенные коды. Код, зашитый в вашей обработке, в новой базе не найдет ничего.

Вывод: жесткая привязка к коду или наименованию (так называемый "хардкод") — это мина замедленного действия в вашем программном коде. Решение этой проблемы существует, и оно встроено в платформу. Это — предопределенные элементы.

Решение 1: Использование предопределенных элементов

Предопределенные элементы — это элементы справочников (и некоторых других объектов), которые создаются не пользователем в режиме «Предприятие», а разработчиком на этапе конфигурирования. Они являются частью метаданных конфигурации.

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

Пример обращения:


// Вместо этого:
СсылкаНаВалюту = Справочники.Валюты.НайтиПоНаименованию("Доллар США");

// Используем это:
СсылкаНаВалюту = Справочники.Валюты.ДолларСША;

Такой код будет работать всегда, даже если пользователь переименует валюту в "Бакс" и изменит ее код. Платформа всегда "знает", какой элемент в базе данных соответствует предопределенному элементу ДолларСША.

Как сделать существующий элемент предопределенным?

Часто бывает, что база уже работает, пользователи создали нужные элементы вручную, и только потом возникает необходимость привязаться к ним в коде. Удалять и создавать заново — не вариант. Для таких случаев в платформе (начиная с версии 8.3.3) существует стандартный реквизит ИмяПредопределенныхДанных.

Рассмотрим по шагам, как это сделать:

  1. Откройте конфигуратор и в нужном справочнике на вкладке "Предопределенные" создайте новый предопределенный элемент. Задайте ему Имя (например, ОсновнойСклад) — это то имя, по которому вы будете обращаться к нему из кода. Наименование и код можно оставить пустыми.
  2. Сохраните конфигурацию. Платформа создаст в базе данных новый, пустой элемент, связанный с вашим предопределенным именем.
  3. Теперь нам нужно связать наше предопределенное имя не с этим новым элементом, а с тем, который уже был создан пользователем. Для этого напишем небольшую обработку.

Пример кода для обработки:


// Найдем элемент, созданный пользователем (например, по наименованию, в последний раз)
НайденныйЭлемент = Справочники.Склады.НайтиПоНаименованию("Главный склад");

Если НЕ НайденныйЭлемент.Пустая() Тогда
    // Получим объект этого элемента
    ОбъектЭлемента = НайденныйЭлемент.ПолучитьОбъект();
    
    // Установим ему имя предопределенных данных, которое мы задали в конфигураторе
    ОбъектЭлемента.ИмяПредопределенныхДанных = "ОсновнойСклад";
    
    // Записываем изменения
    ОбъектЭлемента.Записать();

    // Теперь можно удалить пустой элемент, который создала система при обновлении
    // Его можно найти по пустому наименованию или по ссылке Справочники.Склады.ОсновнойСклад
    // до выполнения этого кода.
КонецЕсли;

После выполнения этого кода ссылка Справочники.Склады.ОсновнойСклад будет указывать на ваш старый, созданный пользователем элемент "Главный склад".

Нюанс: Настройка "Обновление предопределенных данных"

У справочника в свойствах есть важная настройка: Обновление предопределенных данных. Она имеет два основных значения:

Когда же нужен второй вариант? Этот режим критически важен в сложных архитектурах:

Важно понимать: давать совет "всегда ставьте 'Не обновлять автоматически'" — неверно. Для большинства типовых конфигураций в простом режиме использования настройка "Авто" является штатной и правильной.

Как программно получить список всех предопределенных имен?

Иногда требуется перебрать все предопределенные элементы, которые есть в конфигурации, независимо от того, созданы ли они в базе данных. Например, для какой-то проверки или инициализации. Для этого существует специальный метод объекта метаданных:


// Получаем массив строк с именами предопределенных элементов
МассивИмен = Метаданные.Справочники.ВидыЦен.ПолучитьИменаПредопределенных();

// Теперь мы можем перебрать их
Для Каждого Имя Из МассивИмен Цикл
    // Обратиться к самому элементу можно через квадратные скобки
    СсылкаНаЭлемент = Справочники.ВидыЦен[Имя];
    Сообщить("Обрабатывается предопределенный элемент: " + СсылкаНаЭлемент);
КонецЦикла;

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

Альтернативные подходы

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

Решение 2: Обращение по УИД (GUID)

Можно один раз получить уникальный идентификатор (УИД) нужного элемента и зашить его в код. УИД не меняется пользователем и уникален.


// Где-то в коде мы сохранили УИД нужного элемента
УИД_НужногоЭлемента = Новый УникальныйИдентификатор("e12a3b45-67c8-90d1-e23f-456789abcdef");

// Обращаемся к нему
Ссылка = Справочники.Номенклатура.ПолучитьСсылку(УИД_НужногоЭлемента);

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

Решение 3: Специализированные хранилища настроек

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

Эти методы хороши тем, что отделяют логику настроек от бизнес-данных, делая систему более гибкой.

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

← На главную