Почему не работает запрос в расширении 1С и в чем разница между параметром и функцией ПредопределенноеЗначение?

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

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

Проблема 1: Ошибка конструктора запросов в расширении

Разберем ситуацию, когда вы пишете запрос к табличной части Партнеры.КонтактнаяИнформация внутри расширения. Текст запроса может выглядеть следующим образом:


ВЫБРАТЬ ПЕРВЫЕ 1
    ПартнерыКонтактнаяИнформация.Значение КАК Адрес
ИЗ
    Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
ГДЕ
    ПартнерыКонтактнаяИнформация.Ссылка = &Ссылка
    И ПартнерыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес);

Этот код успешно выполняется, но при попытке открыть его через Конструктор запроса система выдает ошибку. Проанализируем причину: конструктор запросов является визуальным инструментом, который перед отрисовкой схемы проверяет наличие всех объектов в текущем контексте метаданных. Если вы создали расширение и заимствовали в него только справочник Партнеры, но забыли добавить в расширение табличную часть КонтактнаяИнформация или конкретный реквизит Тип, конструктор не сможет верифицировать обращение к этим полям.

Решение: Для корректной работы конструктора необходимо заимствовать в расширение все объекты метаданных, участвующие в запросе. Если вы обращаетесь к полю Тип, оно должно быть добавлено в расширение вместе со своим типом данных (перечислением). Если заимствование всех объектов нецелесообразно, правку запроса следует выполнять вручную или использовать внешние консоли запросов, которые менее требовательны к контексту расширения.

Проблема 2: Пустой результат при передаче параметра перечисления

Рассмотрим второй вариант кода, который часто вызывает затруднения у разработчиков:


Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
               |    ПартнерыКонтактнаяИнформация.Значение КАК Адрес
               |ИЗ
               |    Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
               |ГДЕ
               |    ПартнерыКонтактнаяИнформация.Ссылка = &Ссылка
               |    И ПартнерыКонтактнаяИнформация.Тип = &ТипАдрес";

Запрос.УстановитьПараметр("ТипАдрес", Перечисления.ТипыКонтактнойИнформации.Адрес);

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

Преимущество функции ПредопределенноеЗначение

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


// Вместо обращения к коллекции Перечисления напрямую:
Запрос.УстановитьПараметр("ТипАдрес", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес"));

Разберем, в чем принципиальная разница:

  1. Перечисления.ТипыКонтактнойИнформации.Адрес — это прямое обращение к менеджеру значения. Платформа берет готовую ссылку из памяти сервера приложений.
  2. ПредопределенноеЗначение("...") — это метод, который заставляет платформу вычислить ссылку по ее строковому имени (полному пути) непосредственно в момент обращения. Это гарантирует, что будет получена актуальная ссылка, валидная для текущего сеанса и всех активных расширений.

Именно поэтому использование строкового описания предопределенного значения работает стабильнее в условиях сложной архитектуры расширений.

Дополнительные методы отладки: ВЫРАЗИТЬ и Кэширование

Если даже после замены параметра на ПредопределенноеЗначение запрос продолжает возвращать пустой результат, проанализируем ситуацию с точки зрения типов данных СУБД. В типовых конфигурациях, таких как УТ 11 или ERP, поле Тип в контактной информации может иметь составной тип или интерпретироваться платформой неоднозначно при наложении расширения.

В таких случаях помогает явное приведение типа в тексте запроса с помощью оператора ВЫРАЗИТЬ:


ГДЕ
    ВЫРАЗИТЬ(ПартнерыКонтактнаяИнформация.Тип КАК Перечисление.ТипыКонтактнойИнформации) = &ТипАдрес

Это подсказывает оптимизатору SQL, с какой таблицей перечислений нужно производить соединение, и исключает ошибки типизации на уровне базы данных.

Важный нюанс по кэшированию: Работа с расширениями в 1С иногда сопровождается "глюками" кэша сеансов. Если код написан верно, объекты заимствованы, но Значение1 <> Значение1, попробуйте перезагрузить рабочий процесс сервера 1С или обновить конфигурацию базы данных с очисткой серверного кэша. Платформа 8.3 иногда хранит старые описания типов предопределенных данных, что мешает корректному сравнению ссылок в запросе.

Итоги и рекомендации

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

  1. Заимствуйте метаданные полностью: если используете таблицу, заимствуйте и ее реквизиты, и типы данных этих реквизитов (справочники, перечисления).
  2. Используйте безопасное получение ссылок: метод ПредопределенноеЗначение() со строковым параметром является более надежным в расширениях, чем прямое обращение к коллекции Перечисления.
  3. Специфика Контактной Информации: помните, что в современных версиях БСП (используемых в УТ 11.5) поле Значение может содержать JSON. Если вам нужно простое строковое представление адреса, используйте поле Представление.
  4. Проверяйте составные типы: при возникновении проблем с условиями ГДЕ, применяйте ВЫРАЗИТЬ для приведения поля к конкретному типу перечисления.
← На главную