Как в запросе расширения 1С получить доступ к реквизитам документа через поле другого объекта?

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

При разработке в среде 1С, особенно при использовании расширений, можно столкнуться с неочевидным поведением платформы. Одна из таких ситуаций — когда в запросе, написанном в модуле расширения, не удается получить доступ к реквизитам документа через точку. Например, мы пытаемся получить дату документа Заказ из реквизита справочника Назначение, но платформа «не видит» поле Дата.

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

Выясняем причину: особенность работы с составными типами в расширениях

Корень проблемы кроется в том, как платформа 1С обрабатывает метаданные объектов с составными типами данных в контексте расширения. Реквизит, который может ссылаться на объекты разных типов (например, на Документ.ЗаказПокупателя и Документ.ЗаказПоставщику), имеет составной тип.

Когда мы добавляем в расширение объект с таким реквизитом, платформа не всегда корректно передает полную информацию о структуре всех возможных типов в движок запросов. В результате, для запроса поле Назначение.Заказ выглядит не как ссылка на конкретный документ (ДокументСсылка.ЗаказПокупателя), а как абстрактная ЛюбаяСсылка (AnyRef).

У типа ЛюбаяСсылка нет своих реквизитов, таких как Дата, Номер или Контрагент. Поэтому, когда мы пытаемся обратиться к ним через точку, система не знает, из какой таблицы базы данных их нужно извлекать. Интересно, что в основной конфигурации или во внешней обработке тот же самый запрос может работать корректно, так как там контекст метаданных полный. В расширении же он оказывается ограниченным.

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

Решение 1: Явное приведение типа с помощью функции ВЫРАЗИТЬ

Это самый надежный и часто используемый метод для решения подобных проблем. Функция ВЫРАЗИТЬ() в языке запросов 1С позволяет явно указать системе, какого типа данные содержатся в поле. Таким образом, мы помогаем движку запросов правильно интерпретировать ссылку и получить доступ к ее реквизитам.

Как это работает? Мы "оборачиваем" наше поле в функцию ВЫРАЗИТЬ и указываем нужный тип документа.

Посмотрим на пример. Исходный запрос, который не работает в расширении:


ВЫБРАТЬ
    Назначение.Заказ.Дата КАК ДатаЗаказа,
    Назначение.Заказ.Номер КАК НомерЗаказа
ИЗ
    Справочник.Назначения КАК Назначение

Чтобы его исправить, применим функцию ВЫРАЗИТЬ. Мы знаем, что в поле Заказ находится ссылка на документ ЗаказПокупателя.


ВЫБРАТЬ
    ВЫРАЗИТЬ(Назначение.Заказ КАК Документ.ЗаказПокупателя).Дата КАК ДатаЗаказа,
    ВЫРАЗИТЬ(Назначение.Заказ КАК Документ.ЗаказПокупателя).Номер КАК НомерЗаказа
ИЗ
    Справочник.Назначения КАК Назначение

В этом варианте мы прямо говорим системе: «считай, что в поле Назначение.Заказ находится ссылка на Документ.ЗаказПокупателя, и возьми из него реквизиты Дата и Номер». После этого запрос будет выполнен корректно.

Оптимизация с помощью вложенного запроса. Если нужно получить много реквизитов из связанного документа, многократное использование ВЫРАЗИТЬ может сделать код громоздким. В этом случае удобно использовать вложенный запрос, чтобы выполнить приведение типа один раз:


ВЫБРАТЬ
    ДанныеЗаказов.ЗаказСсылка.Дата КАК ДатаЗаказа,
    ДанныеЗаказов.ЗаказСсылка.Номер КАК НомерЗаказа,
    ДанныеЗаказов.ЗаказСсылка.Контрагент КАК Контрагент
ИЗ
    (ВЫБРАТЬ
        ВЫРАЗИТЬ(Назначение.Заказ КАК Документ.ЗаказПокупателя) КАК ЗаказСсылка
    ИЗ
        Справочник.Назначения КАК Назначение) КАК ДанныеЗаказов

Этот подход делает основной запрос более чистым и читаемым.

Решение 2: Использование явного ЛЕВОГО СОЕДИНЕНИЯ (LEFT JOIN)

Обращение к реквизитам через точку — это, по сути, неявное (виртуальное) соединение таблиц, которое выполняет сама платформа. Когда этот механизм дает сбой, мы можем выполнить соединение таблиц явно с помощью конструкции ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN).

Этот способ часто оказывается не только более надежным, но и более производительным, так как план выполнения запроса становится более очевидным для СУБД.

Как это работает? Мы соединяем нашу исходную таблицу (Справочник.Назначения) с таблицей нужного нам документа (Документ.ЗаказПокупателя) по условию равенства ссылок.

Давайте перепишем наш запрос с использованием соединения:


ВЫБРАТЬ
    ЗаказПокупателя.Дата КАК ДатаЗаказа,
    ЗаказПокупателя.Номер КАК НомерЗаказа,
    ЗаказПокупателя.Контрагент КАК Контрагент
ИЗ
    Справочник.Назначения КАК Назначение
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказПокупателя КАК ЗаказПокупателя
        ПО Назначение.Заказ = ЗаказПокупателя.Ссылка

В этом запросе мы явно связываем таблицы по полю Назначение.Заказ и полю Ссылка из таблицы документа. После выполнения соединения все реквизиты документа ЗаказПокупателя становятся доступны напрямую через псевдоним таблицы ЗаказПокупателя. Этот метод полностью исключает неоднозначность с типами и является отличной альтернативой функции ВЫРАЗИТЬ.

Дополнительные рекомендации, которые могут помочь

Хотя два описанных выше способа являются основными для решения проблемы, стоит упомянуть еще несколько шагов, которые могут быть полезны при работе с подобными ошибками.

  1. Очистка кэша. Иногда конфигуратор и клиент "запоминают" устаревшую структуру метаданных. Очистка кэша может решить множество необъяснимых проблем. Хотя в данном конкретном случае это может и не помочь, это всегда хороший первый шаг. Для этого нужно удалить содержимое папок в каталоге %APPDATA%\1C\1cv8.
  2. Проверка режима совместимости. Устаревшие режимы совместимости конфигурации могут сохранять старое поведение платформы, включая ошибки. Если есть возможность, попробуйте обновить режим совместимости расширения или основной конфигурации до более актуальной версии.
  3. Проверка наличия всех типов в расширении. Убедитесь, что все типы документов, которые могут быть в составном реквизите, добавлены в расширение. Если расширение "не знает" о существовании какого-то типа, оно не сможет корректно обработать ссылку на него.

Подводя итог, можно сказать, что проблема невидимости реквизитов в запросах расширений — это известная особенность платформы, связанная с обработкой составных типов. Наиболее эффективными и правильными решениями являются явное приведение типов с помощью ВЫРАЗИТЬ или замена неявного соединения через точку на явное ЛЕВОЕ СОЕДИНЕНИЕ. Эти подходы позволяют создать надежный и предсказуемый код, который будет корректно работать в контексте любого расширения.

← На главную