Как правильно установить ссылку на элемент справочника в параметр запроса 1С?

Программист 1С v8.3 (Обычные формы)
← На главную

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

Разбор типичной ошибки: Выборка vs Ссылка

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


Запрос.УстановитьПараметр("Склад", Справочники.Склады.Выбрать("ВременныйСклад"));

Причина ошибки кроется в непонимании возвращаемых типов данных. Метод Выбрать() возвращает объект типа СправочникВыборка, который предназначен для итеративного обхода элементов в цикле. Запрос же в качестве параметра (если в условии ГДЕ стоит сравнение через "=") ожидает конкретную ссылку — тип СправочникСсылка.Склады. Чтобы исправить это, нам необходимо сначала получить ссылку на конкретный элемент базы данных.

Способ 1. Поиск по наименованию или коду

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


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

// Обязательная проверка на наличие элемента
Если Не СкладСсылка.Пустая() Тогда
    Запрос.УстановитьПараметр("Склад", СкладСсылка);
Иначе
    Сообщить("Склад с наименованием 'ВременныйСклад' не найден в базе!");
КонецЕсли;

Важный нюанс: метод НайтиПоНаименованию всегда возвращает ссылку. Если элемент не найден, возвращается ПустаяСсылка. Поэтому проверка Если СкладСсылка <> Неопределено здесь будет ошибочной, так как ссылка никогда не равна Неопределено. Правильно использовать метод Пустая().

Рассмотрим риски этого подхода. Использование «жестко прописанных» строк (хардкод) в коде — это плохая практика. Если пользователь переименует «Временный Склад» в «Склад временного хранения», ваш алгоритм перестанет работать. Аналогичная проблема существует и при поиске по коду.

Способ 2. Использование предопределенных элементов

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

  1. Надежность: пользователь не сможет просто так удалить этот элемент.
  2. Производительность: обращение к предопределенному элементу происходит мгновенно, без дополнительных запросов к БД.
  3. Удобство в запросе: такой элемент можно вставить прямо в текст запроса, вообще не используя УстановитьПараметр.

Пример использования в коде 1С:


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

Пример использования непосредственно в тексте запроса:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   Остатки.Номенклатура,
    |   Остатки.КоличествоОстаток
    |ИЗ
    |   РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
    |ГДЕ
    |   Остатки.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ВременныйСклад)";

Использование конструкции ЗНАЧЕНИЕ(...) внутри запроса — это наиболее эффективный способ с точки зрения СУБД, так как платформа подставляет внутренний идентификатор (GUID) на этапе компиляции запроса.

Способ 3. Использование констант и настроек программы

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

Алгоритм действий:

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

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

Этот подход делает систему гибкой: если склад изменится, программисту не придется лезть в код и менять «ВременныйСклад» на что-то другое.

Способ 4. Поиск по уникальному идентификатору (GUID)

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


// Узнать GUID можно программно или через консоль запросов
ИдентификаторСклада = Новый УникальныйИдентификатор("550e8400-e29b-41d4-a716-446655440000");
СкладСсылка = Справочники.Склады.ПолучитьСсылку(ИдентификаторСклада);

Запрос.УстановитьПараметр("Склад", СкладСсылка);

Даже если пользователь изменит название склада или его код, ссылка по GUID останется рабочей.

Оптимизация: Избегаем поиска в цикле

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

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

Как сделать правильно:

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

Пример для динамического списка:


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

Заключение

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

← На главную