В процессе разработки на платформе 1С:Предприятие 8 каждый программист рано или поздно сталкивается с необходимостью обратиться к конкретному элементу справочника. Например, нам нужно программно подставить «Основной склад» в документ или выбрать специфический тип номенклатуры для расчетов. Самый простой и очевидный путь — использовать метод НайтиПоКоду(). Однако, как справедливо замечают опытные разработчики, этот путь ведет к хрупкости системы. Давайте разберем, почему «жесткое» кодирование строковых кодов в конфигурации считается «плохим тоном», и какие архитектурно верные альтернативы мы можем применить в своей работе.
Прежде чем мы перейдем к решениям, проанализируем ситуацию и выясним причины, по которым поиск по коду (или, что еще хуже, по наименованию) может привести к ошибкам:
Рассмотрим подробнее современные и надежные способы хранения ссылок на нужные нам элементы.
В версии платформы 8.3 механизмы работы с предопределенными данными были значительно расширены. Если раньше мы создавали предопределенные элементы только в Конфигураторе, то теперь мы можем программно связывать существующие элементы базы данных с именами предопределенных данных.
Разберем, как это работает. Мы можем использовать метод УстановитьИмяПредопределенныхДанных(), чтобы превратить обычный элемент, созданный пользователем, в «псевдо-предопределенный». Это позволяет нам обращаться к нему в коде максимально лаконично:
// Обращение к элементу как к свойству справочника
СкладОбъект = Справочники.Склады.ОсновнойСклад;
Этот способ идеален тем, что платформа сама берет на себя заботу о кэшировании и быстром доступе к ссылке. Если нам нужно программно связать элемент, мы используем следующий подход:
ЭлементСправочника = Справочники.Склады.НайтиПоКоду("УТ-00001");
ОбъектСклада = ЭлементСправочника.ПолучитьОбъект();
ОбъектСклада.ИмяПредопределенныхДанных = "ОсновнойСклад";
ОбъектСклада.Записать();
Часто бывает так, что элементов много, и они могут меняться в зависимости от организации или пользователя. В этом случае мы создаем специальный Регистр сведений (например, «НастройкиПоУмолчанию» или «СистемныеНастройки»).
Проанализируем структуру такого регистра:
ИмяНастройки (Тип: Строка или План видов характеристик).Значение (Тип: ЛюбаяСсылка).Теперь создадим в общем модуле функцию-обертку, которая будет возвращать нам нужное значение. Чтобы не нагружать базу данных постоянными запросами, обязательно установим у модуля свойство «Повторное использование возвращаемых значений».
Функция ПолучитьСсылкуНаНастройку(ИмяНастройки) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Настройки.Значение КАК Значение
|ИЗ
| РегистрСведений.СистемныеНастройки КАК Настройки
|ГДЕ
| Настройки.ИмяНастройки = &ИмяНастройки";
Запрос.УстановитьПараметр("ИмяНастройки", ИмяНастройки);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
Возврат Выборка.Значение;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Преимущество этого метода в том, что администратор системы может в любой момент изменить привязку в пользовательском режиме без участия программиста.
Это, пожалуй, самый элегантный архитектурный способ в 1С. Функциональные опции позволяют привязать значение (ссылку на справочник) к ресурсу регистра сведений. В программном коде мы просто проверяем значение опции:
// Получаем значение функциональной опции
Склад = ПолучитьФункциональнуюОпцию("ОсновнойСкладОрганизации");
Если опция привязана к параметру (например, к конкретной организации), платформа автоматически подставит нужное значение из регистра. Это исключает необходимость писать сложные запросы в каждом модуле.
Если нам нужно решение «дешево и сердито», но надежнее, чем поиск по коду, мы можем добавить в справочник дополнительный реквизит ИдентификаторДляРазработчика (строка, индексировать). В этом поле мы записываем понятное имя, например, «ГЛАВНЫЙ_ОФИС».
Почему это лучше кода? Код справочника обычно виден пользователю, он может участвовать в автонумерации или бизнес-процессах печати. Наш новый реквизит можно скрыть с формы, защитив его от случайного изменения.
// Пример поиска по системному идентификатору
Ссылка = Справочники.Склады.НайтиПоРеквизиту("ИдентификаторДляРазработчика", "ГЛАВНЫЙ_ОФИС");
Если Ссылка.Пустая() Тогда
// Обработка ситуации, если элемент не найден
КонецЕсли;
Для одиночных, глобальных настроек (например, «Валюта регламентированного учета» или «Организация по умолчанию») идеально подходят Константы. Обращение к ним максимально быстрое, а платформа предоставляет удобные формы для их заполнения.
// Чтение константы
НашаОрганизация = Константы.ОсновнаяОрганизация.Получить();
Выясним, как сделать работу с такими ссылками максимально быстрой. Если ваша обработка выполняет поиск в цикле (например, при импорте данных), никогда не используйте поиск внутри цикла. Проанализируем правильный алгоритм:
Соответствие (Map).
// Оптимизированный поиск через Соответствие
ТаблицаСопоставления = Новый Соответствие;
Выборка = Справочники.Склады.Выбрать();
Пока Выборка.Следующий() Цикл
ТаблицаСопоставления.Вставить(Выборка.ИдентификаторДляРазработчика, Выборка.Ссылка);
КонецЦикла;
// В цикле обработки данных
ТекущаяСсылка = ТаблицаСопоставления.Получить("НУЖНЫЙ_СКЛАД");
Подведем итог. Использование НайтиПоКоду() допустимо только в разовых внешних обработках или в ситуациях, когда вы на 100% уверены в неизменности структуры данных (например, в жестко регламентированных классификаторах). Для разработки тиражных решений или сложных корпоративных систем всегда выбирайте между предопределенными элементами, регистрами настроек или функциональными опциями. Это сделает ваш код надежным, читаемым и легким в сопровождении.