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

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

В процессе разработки на платформе 1С:Предприятие мы часто сталкиваемся с задачами, когда в качестве параметра запроса передается ссылка на документ или справочник, тип которого становится известен только во время выполнения программы. Классическая попытка обращения к реквизиту через точку, например Т.Документ.Реквизит, вызывает ошибку, если тип объекта не является строго заданным для данного поля или если реквизит отсутствует у некоторых объектов из перечня возможных типов.

Разбор проблемы: почему не работает конструкция ССЫЛКА и ВЫРАЗИТЬ?

Многие разработчики начинают с использования конструкции ВЫБОР КОГДА ССЫЛКА.... Однако при работе с полями составного типа 1С требует строгого соблюдения типизации. Когда мы используем ВЫБОР, семантический анализатор запросов пытается привести все возможные варианты к одному типу данных. Если мы пытаемся принудительно «превратить» неизвестный объект в конкретный документ с помощью ВЫРАЗИТЬ, мы можем получить ошибку «Несовместимые типы», так как система ожидает единообразия в структуре выборки.

Решение задачи: использование ЛЕВОГО СОЕДИНЕНИЯ

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

Давайте разберем по шагам, как правильно реализовать этот подход:

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

Практический пример реализации запроса

Рассмотрим код, который демонстрирует этот подход на практике. Мы предполагаем, что у нас есть параметр &Регистратор, который мы хотим «проверить» на наличие реквизита Подразделение:


ВЫБРАТЬ
    &Регистратор КАК ДокументРегистратор
ПОМЕСТИТЬ Т
;

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

В данном запросе, если в Т.ДокументРегистратор находится документ, отличный от ЗаказКлиента, условие соединения Т.ДокументРегистратор = ЗаказКлиента.Ссылка не будет выполнено, и поле Подразделение вернет NULL. Это поведение является корректным с точки зрения СУБД.

Обработка результатов: NULL vs Неопределено

Часто в бизнес-логике требуется, чтобы отсутствие данных было представлено значением Неопределено, а не NULL. Чтобы добиться такого результата, мы можем обернуть выборку в дополнительную логику:


ВЫБРАТЬ 
    Документы.ДокументРегистратор КАК ДокументРегистратор,
    ВЫБОР 
        КОГДА ЗаказКлиента.Ссылка ЕСТЬ NULL ТОГДА НЕОПРЕДЕЛЕНО 
        ИНАЧЕ ЗаказКлиента.Подразделение 
    КОНЕЦ КАК Подразделение
ИЗ
    ВтДокументы КАК Документы
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК ЗаказКлиента
        ПО Документы.ДокументРегистратор = ЗаказКлиента.Ссылка

Почему этот способ лучше?

Проанализируем преимущества данного подхода:

Используя этот подход, вы навсегда забудете о проблемах с типизацией в запросах при работе с объектами метаданных и обеспечите стабильную работу вашей конфигурации в любых условиях!

← На главную