Почему запрос 1С работает в консоли запросов, но не находит данные в коде формы?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Причина №1: Несоответствие типов (Строка vs Ссылка)

Это самая распространенная причина. Проанализируем ситуацию: в консоли запросов, когда вы настраиваете параметры, вы чаще всего выбираете конкретный элемент справочника из списка. В этот момент в параметр запроса передается объект типа СправочникСсылка. Однако в коде программисты часто передают Объект.Наименование или Объект.ФИО, что является типом Строка.

Для системы 1С сравнение Ссылка = Строка всегда будет давать результат Ложь. Запрос не выдаст ошибку исполнения, он просто вернет пустой результат (0 строк), так как ни одна ссылка в базе не равна текстовой строке. Посмотрим на пример кода, который вызывает проблему:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Таксофоны.Номер КАК Номер
    |ИЗ
    |    Справочник.Таксофоны КАК Таксофоны
    |ГДЕ
    |    Таксофоны.Абоненты.ФИО = &ФИО";

// ОШИБКА: передается строка, а в поле ФИО, вероятно, хранится Ссылка
Запрос.УстановитьПараметр("ФИО", Объект.Наименование); 
РезультатЗапроса = Запрос.Выполнить();

Чтобы исправить эту ситуацию, нам необходимо привести передаваемый параметр к тому же типу, который хранится в базе данных. Если в поле ФИО хранится ссылка на другой справочник, нам нужно сначала найти эту ссылку по наименованию:


// Правильный подход: получаем ссылку перед установкой параметра
АбонентСсылка = Справочники.Абоненты.НайтиПоНаименованию(Объект.Наименование);

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

Причина №2: Особенности отладки выборки запроса

Рассмотрим ситуацию, когда при отладке метода Следующий() возникает ошибка «Поле объекта не обнаружено». Выясним причину этого поведения. Проблема часто кроется в том, что разработчик добавляет выражение ВыборкаДетальныеЗаписи.Следующий() в окно Табло или Вычислить выражение.

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

Рекомендация: Никогда не вызывайте методы перемещения курсора (Следующий(), Прочитать()) в окне вычисления выражений. Чтобы проверить, есть ли данные в результате запроса, используйте свойство РезультатЗапроса.Пустой() или метод ВыборкаДетальныеЗаписи.Количество().

Причина №3: Невидимые символы и лишние пробелы

Проанализируем ситуацию, когда типы совпадают (оба — строки), но запрос все равно ничего не находит. При вводе данных в форму пользователи могут случайно скопировать неразрывные пробелы (символ с кодом 160), знаки табуляции или просто оставить пробелы в конце строки. Визуально в функции Сообщить() строки будут выглядеть одинаково, но для поискового движка SQL это разные значения.

Для решения этой проблемы рекомендуется всегда «очищать» строковые параметры перед передачей в запрос. Рассмотрим пример:


// Используем СокрЛП для удаления пробелов по краям
ПараметрПоиска = СокрЛП(Объект.Наименование);
Запрос.УстановитьПараметр("ФИО", ПараметрПоиска);

Также стоит помнить, что в запросе можно использовать оператор ПОДОБНО, если вы не уверены в точном совпадении строк, хотя это может замедлить работу системы на больших объемах данных.

Как проверить тип данных в запросе?

Если вы запутались и не понимаете, какой тип ожидает запрос, используйте отладочный прием прямо в консоли запросов. Добавьте в поле выбора функцию ТИПЗНАЧЕНИЯ:


ВЫБРАТЬ
    ТИПЗНАЧЕНИЯ(Таксофоны.Абоненты.ФИО) КАК ТипПоляИзБазы,
    Таксофоны.Номер КАК Номер
ИЗ
    Справочник.Таксофоны КАК Таксофоны

Запустив такой запрос в консоли, вы увидите реальный тип данных в колонке ТипПоляИзБазы. Если там написано «Абоненты (Справочник ссылка)», а вы передаете строку — причина найдена.

Итоги и лучшие практики

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

  1. Всегда проверяйте типы. Если в метаданных поле является ссылочным, передавайте в параметр только Ссылку.
  2. Используйте поиск перед запросом. Если у вас на входе только текст, получите ссылку методом НайтиПоНаименованию() или НайтиПоКоду(), и только потом подставляйте её в запрос.
  3. Будьте осторожны с отладчиком. Не вычисляйте методы, изменяющие состояние объектов (как Следующий()), в окне просмотра переменных.
  4. Очищайте входные данные. Применение СокрЛП() к строковым параметрам — это «правило хорошего тона» в разработке на 1С.
  5. Проверяйте результат на пустоту. Перед началом цикла обхода выборки всегда полезно проверить РезультатЗапроса.Пустой(), чтобы понимать, на каком этапе «пропадают» данные.

Соблюдение этих простых правил сэкономит вам часы отладки и сделает ваш код более надежным и понятным для коллег.

← На главную