При разработке алгоритмов на платформе 1С:Предприятие одной из самых частых задач является фильтрация данных в запросе по конкретному элементу справочника (например, по определенному складу, организации или типу номенклатуры). Однако начинающие разработчики часто сталкиваются с ошибками типизации при попытке передать объект в параметр запроса. Рассмотрим подробнее, почему возникают такие ошибки и какие существуют методики для надежного и производительного решения этой задачи.
Проанализируем ситуацию, с которой столкнулся автор темы. Попытка установить параметр следующим образом приводит к ошибке:
Запрос.УстановитьПараметр("Склад", Справочники.Склады.Выбрать("ВременныйСклад"));
Причина ошибки кроется в непонимании возвращаемых типов данных. Метод Выбрать() возвращает объект типа СправочникВыборка, который предназначен для итеративного обхода элементов в цикле. Запрос же в качестве параметра (если в условии ГДЕ стоит сравнение через "=") ожидает конкретную ссылку — тип СправочникСсылка.Склады. Чтобы исправить это, нам необходимо сначала получить ссылку на конкретный элемент базы данных.
Самый простой и очевидный способ — найти элемент по его текстовому представлению или коду. Разберем, как это реализовать правильно, учитывая возможные исключительные ситуации.
// Поиск по наименованию
СкладСсылка = Справочники.Склады.НайтиПоНаименованию("ВременныйСклад");
// Обязательная проверка на наличие элемента
Если Не СкладСсылка.Пустая() Тогда
Запрос.УстановитьПараметр("Склад", СкладСсылка);
Иначе
Сообщить("Склад с наименованием 'ВременныйСклад' не найден в базе!");
КонецЕсли;
Важный нюанс: метод НайтиПоНаименованию всегда возвращает ссылку. Если элемент не найден, возвращается ПустаяСсылка. Поэтому проверка Если СкладСсылка <> Неопределено здесь будет ошибочной, так как ссылка никогда не равна Неопределено. Правильно использовать метод Пустая().
Рассмотрим риски этого подхода. Использование «жестко прописанных» строк (хардкод) в коде — это плохая практика. Если пользователь переименует «Временный Склад» в «Склад временного хранения», ваш алгоритм перестанет работать. Аналогичная проблема существует и при поиске по коду.
Если конкретный склад (или другой объект) критически важен для логики системы и должен существовать всегда, правильнее всего сделать его предопределенным в конфигураторе. Это дает колоссальные преимущества:
УстановитьПараметр.Пример использования в коде 1С:
// Прямое обращение через метаданные
Запрос.УстановитьПараметр("Склад", Справочники.Склады.ВременныйСклад);
Пример использования непосредственно в тексте запроса:
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура,
| Остатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
|ГДЕ
| Остатки.Склад = ЗНАЧЕНИЕ(Справочник.Склады.ВременныйСклад)";
Использование конструкции ЗНАЧЕНИЕ(...) внутри запроса — это наиболее эффективный способ с точки зрения СУБД, так как платформа подставляет внутренний идентификатор (GUID) на этапе компиляции запроса.
Выясним причину, почему разработчики часто избегают предопределенных элементов: иногда склад уже существует в рабочей базе, в нем накоплено много движений, и делать его предопределенным «задним числом» сложно (требуется объединение дублей). В таких случаях лучшим решением будет создание Константы.
Алгоритм действий:
СкладДляРемонта) с типом СправочникСсылка.Склады.
// Получение ссылки из настроек
НужныйСклад = Константы.СкладДляРемонта.Получить();
Запрос.УстановитьПараметр("Склад", НужныйСклад);
Этот подход делает систему гибкой: если склад изменится, программисту не придется лезть в код и менять «ВременныйСклад» на что-то другое.
Если нельзя менять конфигурацию (добавлять константы или элементы), но нужно гарантировать, что поиск по имени не сломается при переименовании, воспользуемся поиском по внутреннему идентификатору (UUID). У каждого объекта в 1С есть уникальный код, который не меняется никогда.
// Узнать GUID можно программно или через консоль запросов
ИдентификаторСклада = Новый УникальныйИдентификатор("550e8400-e29b-41d4-a716-446655440000");
СкладСсылка = Справочники.Склады.ПолучитьСсылку(ИдентификаторСклада);
Запрос.УстановитьПараметр("Склад", СкладСсылка);
Даже если пользователь изменит название склада или его код, ссылка по GUID останется рабочей.
Проанализируем ситуацию с «разукрашкой» (цветовым оформлением списка номенклатуры). В Сообщении 8 упоминается, что проверка склада нужна для раскраски строк. Если вы работаете в обычных формах в событии ПриВыводеСтроки, крайне важно помнить о производительности.
Ни в коем случае нельзя выполнять НайтиПоНаименованию() или выполнять Запрос внутри этого события. Поскольку событие вызывается для каждой строки списка, это приведет к тому, что при прокрутке списка база данных будет «бомбардироваться» сотнями мелких запросов, что вызовет ощутимые «тормоза» у пользователя.
Как сделать правильно:
ПриОткрытии) и сохраните ее в переменную модуля формы.ПриВыводеСтроки используйте уже готовую переменную.Пример для динамического списка:
// Установка параметра для всего списка сразу
Список.Параметры.УстановитьЗначениеПараметра("СкладОтбора", Справочники.Склады.ВременныйСклад);
Мы рассмотрели различные подходы к установке параметров. Подведем итог: для разовых обработок допустим поиск по наименованию с обязательной проверкой Пустая(). Для системных алгоритмов лучше использовать предопределенные элементы или константы. Это обеспечит стабильность работы программы и высокую скорость выполнения запросов. Всегда помните, что тип параметра в коде 1С должен строго соответствовать ожидаемому типу в условии запроса.