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