Разработка в среде 1С:Предприятие часто преподносит сюрпризы, когда один и тот же запрос, успешно протестированный в интерактивной консоли, отказывается выдавать данные при выполнении в программном модуле. Это классическая ситуация, через которую проходит каждый начинающий разработчик. В этой статье мы детально проанализируем причины такого поведения, разберем технические нюансы работы с параметрами и выясним, как избежать подобных ошибок в будущем.
Одной из самых частых причин расхождения результатов является неявная типизация. Рассмотрим ситуацию, описанную в сообщениях форума. Разработчик использует переменную ДанныеЗаполнения в качестве параметра запроса. В контексте процедуры ОбработкаЗаполнения этот объект может принимать совершенно разные формы в зависимости от способа создания документа.
Проанализируем возможные типы переменной ДанныеЗаполнения:
ДанныеЗаполнения попадает объект типа Структура.В консоли запросов программист всегда выбирает конкретную ссылку интерактивно. В коде же, передавая ДанныеЗаполнения без проверки типа, мы рискуем отправить в запрос Структуру. С точки зрения SQL-сервера, сравнение ссылки (GUID) со структурой (которая для него является бессмысленным набором данных) всегда будет ложным (FALSE). В итоге запрос выполняется без ошибок, но возвращает пустой результат.
Для исправления ситуации необходимо всегда проверять тип передаваемого параметра:
Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
Запрос.УстановитьПараметр("Ссылка", ДанныеЗаполнения);
ИначеЕсли ТипЗнч(ДанныеЗаполнения) = Тип("Структура") И ДанныеЗаполнения.Свойство("ДокументОснование") Тогда
Запрос.УстановитьПараметр("Ссылка", ДанныеЗаполнения.ДокументОснование);
КонецЕсли;
Обратим внимание на текст запроса во втором сообщении: ГДЕ СписаниеЗапасов.ДокументОснование.Ссылка = &Ссылка. Здесь кроется вторая серьезная методическая ошибка. Поле ДокументОснование само по себе уже является ссылкой.
Рассмотрим, что происходит «под капотом» платформы при обращении через точку к полю Ссылка:
Ссылка).Правильный и наиболее эффективный вариант написания условия выглядит так:
Запрос.Текст =
"ВЫБРАТЬ
| СписаниеЗапасов.Ссылка КАК Ссылка
|ИЗ
| Документ.СписаниеЗапасов КАК СписаниеЗапасов
|ГДЕ
| СписаниеЗапасов.ДокументОснование = &Ссылка";
В данном случае сравнение идет напрямую со значением в физической таблице СписаниеЗапасов, без привлечения данных из других таблиц.
Как справедливо заметили участники обсуждения в сообщении №9, часто проблема кроется в банальной невнимательности. В первом варианте (для консоли) автор использовал фильтр по полю Корреспонденция, а в программном коде — по полю ДокументОснование.
Выясним причину, почему это критично:
Корреспонденция и ДокументОснование могут содержать разные ссылки, даже если они визуально похожи.Всегда проверяйте соответствие текста запроса в конфигураторе тому тексту, который вы отлаживали в консоли. Лучшим способом является использование конструктора запросов или копирование текста напрямую, без ручного переписывания.
Проанализируем еще один важный аспект: контекст выполнения. Консоль запросов часто запускается администратором или пользователем с полными правами. Программный же код выполняется под правами текущего пользователя.
Если в системе настроены Ограничения доступа на уровне записей (RLS), то запрос может вести себя следующим образом:
Для диагностики этой проблемы попробуйте выполнить тот же запрос в коде, обернув его в привилегированный режим, или проверьте права пользователя на чтение документа СписаниеЗапасов и всех документов, входящих в состав типа ДокументОснование.
Подводя итог, разберем по шагам алгоритм действий, если ваш запрос «сломался» при переносе в код:
Запрос.УстановитьПараметр передается именно Ссылка, а не Структура, Строка или Число..Ссылка. Сравнивайте ссылочные поля напрямую.ГДЕ в консоли и в коде идентичны. Обратите внимание на использование параметров (например, не перепутаны ли &Ссылка и &Документ).Соблюдение этих простых правил позволит вам быстро находить ошибки в запросах и писать более качественный и производительный код в системе 1С:Предприятие.