При разработке в расширениях системы 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда один и тот же запрос ведет себя по-разному в консоли запросов, основной конфигурации и расширении. Рассмотрим типичную ситуацию на примере конфигурации Управление торговлей 11.5, когда при попытке получить контактную информацию партнера запрос либо выдает ошибку в конструкторе, либо возвращает пустой результат при использовании параметров.
Разберем ситуацию, когда вы пишете запрос к табличной части Партнеры.КонтактнаяИнформация внутри расширения. Текст запроса может выглядеть следующим образом:
ВЫБРАТЬ ПЕРВЫЕ 1
ПартнерыКонтактнаяИнформация.Значение КАК Адрес
ИЗ
Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
ГДЕ
ПартнерыКонтактнаяИнформация.Ссылка = &Ссылка
И ПартнерыКонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес);
Этот код успешно выполняется, но при попытке открыть его через Конструктор запроса система выдает ошибку. Проанализируем причину: конструктор запросов является визуальным инструментом, который перед отрисовкой схемы проверяет наличие всех объектов в текущем контексте метаданных. Если вы создали расширение и заимствовали в него только справочник Партнеры, но забыли добавить в расширение табличную часть КонтактнаяИнформация или конкретный реквизит Тип, конструктор не сможет верифицировать обращение к этим полям.
Решение: Для корректной работы конструктора необходимо заимствовать в расширение все объекты метаданных, участвующие в запросе. Если вы обращаетесь к полю Тип, оно должно быть добавлено в расширение вместе со своим типом данных (перечислением). Если заимствование всех объектов нецелесообразно, правку запроса следует выполнять вручную или использовать внешние консоли запросов, которые менее требовательны к контексту расширения.
Рассмотрим второй вариант кода, который часто вызывает затруднения у разработчиков:
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
| ПартнерыКонтактнаяИнформация.Значение КАК Адрес
|ИЗ
| Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
|ГДЕ
| ПартнерыКонтактнаяИнформация.Ссылка = &Ссылка
| И ПартнерыКонтактнаяИнформация.Тип = &ТипАдрес";
Запрос.УстановитьПараметр("ТипАдрес", Перечисления.ТипыКонтактнойИнформации.Адрес);
Выясним причину, почему такой код может возвращать пустой результат, хотя данные в базе точно есть. Проблема кроется в механизме работы расширений и сопоставлении ссылочных типов. Когда мы передаем значение через Запрос.УстановитьПараметр, мы передаем конкретную ссылку из объектной модели встроенного языка. В некоторых случаях (особенно при динамическом обновлении или некорректном кэшировании метаданных расширения) идентификатор типа данных в расширении может не совпасть с идентификатором в основной базе на уровне SQL-запроса.
Для решения описанной выше проблемы рекомендуется использовать метод ПредопределенноеЗначение. Посмотрим, как изменится код:
// Вместо обращения к коллекции Перечисления напрямую:
Запрос.УстановитьПараметр("ТипАдрес", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес"));
Разберем, в чем принципиальная разница:
Именно поэтому использование строкового описания предопределенного значения работает стабильнее в условиях сложной архитектуры расширений.
Если даже после замены параметра на ПредопределенноеЗначение запрос продолжает возвращать пустой результат, проанализируем ситуацию с точки зрения типов данных СУБД. В типовых конфигурациях, таких как УТ 11 или ERP, поле Тип в контактной информации может иметь составной тип или интерпретироваться платформой неоднозначно при наложении расширения.
В таких случаях помогает явное приведение типа в тексте запроса с помощью оператора ВЫРАЗИТЬ:
ГДЕ
ВЫРАЗИТЬ(ПартнерыКонтактнаяИнформация.Тип КАК Перечисление.ТипыКонтактнойИнформации) = &ТипАдрес
Это подсказывает оптимизатору SQL, с какой таблицей перечислений нужно производить соединение, и исключает ошибки типизации на уровне базы данных.
Важный нюанс по кэшированию: Работа с расширениями в 1С иногда сопровождается "глюками" кэша сеансов. Если код написан верно, объекты заимствованы, но Значение1 <> Значение1, попробуйте перезагрузить рабочий процесс сервера 1С или обновить конфигурацию базы данных с очисткой серверного кэша. Платформа 8.3 иногда хранит старые описания типов предопределенных данных, что мешает корректному сравнению ссылок в запросе.
Подведем итог нашему исследованию. Для того чтобы ваши запросы в расширениях работали стабильно и поддавались редактированию через конструктор, придерживайтесь следующих правил:
ПредопределенноеЗначение() со строковым параметром является более надежным в расширениях, чем прямое обращение к коллекции Перечисления.Значение может содержать JSON. Если вам нужно простое строковое представление адреса, используйте поле Представление.ГДЕ, применяйте ВЫРАЗИТЬ для приведения поля к конкретному типу перечисления.