В процессе разработки на платформе 1С часто возникает задача обратиться к конкретному, заранее известному элементу справочника. Классический пример — использование определенной валюты, типа цен или статьи затрат в алгоритмах. Начинающие разработчики часто решают эту задачу "в лоб", используя поиск по коду или наименованию. Однако такой подход крайне ненадежен и может привести к ошибкам в самый неподходящий момент. Давайте разберемся, почему так происходит и какие существуют правильные и надежные способы решения этой задачи.
Представим, что в коде мы обращаемся к элементу справочника «ВидыЦен» через НайтиПоНаименованию("Оптовая"). Все работает отлично до тех пор, пока пользователь не решит переименовать этот вид цены в "Оптовая (старая)" или просто допустит опечатку. В этот момент ваш код перестанет находить нужный элемент, и логика программы нарушится.
Аналогичная ситуация с поиском по коду через НайтиПоКоду(). Кажется, что код — это нечто статичное, но на практике это не так. Проанализируем основные причины, по которым этот метод также ненадежен:
Вывод: жесткая привязка к коду или наименованию (так называемый "хардкод") — это мина замедленного действия в вашем программном коде. Решение этой проблемы существует, и оно встроено в платформу. Это — предопределенные элементы.
Предопределенные элементы — это элементы справочников (и некоторых других объектов), которые создаются не пользователем в режиме «Предприятие», а разработчиком на этапе конфигурирования. Они являются частью метаданных конфигурации.
Главное их преимущество в том, что к ним можно обращаться из кода напрямую по имени, которое вы задали в конфигураторе. Это имя не зависит от кода, наименования или любого другого реквизита, который может поменять пользователь.
Пример обращения:
// Вместо этого:
СсылкаНаВалюту = Справочники.Валюты.НайтиПоНаименованию("Доллар США");
// Используем это:
СсылкаНаВалюту = Справочники.Валюты.ДолларСША;
Такой код будет работать всегда, даже если пользователь переименует валюту в "Бакс" и изменит ее код. Платформа всегда "знает", какой элемент в базе данных соответствует предопределенному элементу ДолларСША.
Часто бывает, что база уже работает, пользователи создали нужные элементы вручную, и только потом возникает необходимость привязаться к ним в коде. Удалять и создавать заново — не вариант. Для таких случаев в платформе (начиная с версии 8.3.3) существует стандартный реквизит ИмяПредопределенныхДанных.
Рассмотрим по шагам, как это сделать:
ОсновнойСклад) — это то имя, по которому вы будете обращаться к нему из кода. Наименование и код можно оставить пустыми.Пример кода для обработки:
// Найдем элемент, созданный пользователем (например, по наименованию, в последний раз)
НайденныйЭлемент = Справочники.Склады.НайтиПоНаименованию("Главный склад");
Если НЕ НайденныйЭлемент.Пустая() Тогда
// Получим объект этого элемента
ОбъектЭлемента = НайденныйЭлемент.ПолучитьОбъект();
// Установим ему имя предопределенных данных, которое мы задали в конфигураторе
ОбъектЭлемента.ИмяПредопределенныхДанных = "ОсновнойСклад";
// Записываем изменения
ОбъектЭлемента.Записать();
// Теперь можно удалить пустой элемент, который создала система при обновлении
// Его можно найти по пустому наименованию или по ссылке Справочники.Склады.ОсновнойСклад
// до выполнения этого кода.
КонецЕсли;
После выполнения этого кода ссылка Справочники.Склады.ОсновнойСклад будет указывать на ваш старый, созданный пользователем элемент "Главный склад".
У справочника в свойствах есть важная настройка: Обновление предопределенных данных. Она имеет два основных значения:
Когда же нужен второй вариант? Этот режим критически важен в сложных архитектурах:
Важно понимать: давать совет "всегда ставьте 'Не обновлять автоматически'" — неверно. Для большинства типовых конфигураций в простом режиме использования настройка "Авто" является штатной и правильной.
Иногда требуется перебрать все предопределенные элементы, которые есть в конфигурации, независимо от того, созданы ли они в базе данных. Например, для какой-то проверки или инициализации. Для этого существует специальный метод объекта метаданных:
// Получаем массив строк с именами предопределенных элементов
МассивИмен = Метаданные.Справочники.ВидыЦен.ПолучитьИменаПредопределенных();
// Теперь мы можем перебрать их
Для Каждого Имя Из МассивИмен Цикл
// Обратиться к самому элементу можно через квадратные скобки
СсылкаНаЭлемент = Справочники.ВидыЦен[Имя];
Сообщить("Обрабатывается предопределенный элемент: " + СсылкаНаЭлемент);
КонецЦикла;
Этот метод вернет имена даже тех предопределенных элементов, которые пользователь удалил из базы или которые не были созданы из-за настройки "Не обновлять автоматически".
Хотя предопределенные элементы — это стандартный механизм, в некоторых случаях могут быть удобны и другие подходы.
Можно один раз получить уникальный идентификатор (УИД) нужного элемента и зашить его в код. УИД не меняется пользователем и уникален.
// Где-то в коде мы сохранили УИД нужного элемента
УИД_НужногоЭлемента = Новый УникальныйИдентификатор("e12a3b45-67c8-90d1-e23f-456789abcdef");
// Обращаемся к нему
Ссылка = Справочники.Номенклатура.ПолучитьСсылку(УИД_НужногоЭлемента);
Внимание, есть нюанс! Этот метод может дать сбой в сложных сценариях разработки. Если вы создали предопределенный элемент в базе-копии, а затем загрузили конфигурацию (cf-файл) из этой копии в рабочую базу, то УИДы элементов, связанных с одним и тем же предопределенным именем, в этих двух базах будут разными. УИД принадлежит элементу базы данных, а не имени в метаданных. Поэтому этот метод менее надежен, чем обращение по имени предопределенного элемента.
Для хранения ссылок на элементы, которые используются как настройки, можно использовать другие объекты:
ХранилищеЗначения или конкретный тип ссылки).Эти методы хороши тем, что отделяют логику настроек от бизнес-данных, делая систему более гибкой.
В итоге, выбор способа зависит от задачи. Но для надежной привязки логики к конкретным, неизменяемым по своей сути элементам данных (как валюты, единицы измерения, ставки НДС), предопределенные элементы являются самым правильным и надежным механизмом, предоставляемым платформой 1С.