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

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

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

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

Почему нельзя связать Критерий отбора в запросе динамического списка напрямую?

Основная техническая сложность кроется в специфике работы виртуальных таблиц критериев отбора в языке запросов 1С. Критерий отбора в запросе представляет собой виртуальную таблицу, которая требует обязательного входного параметра — значения отбора. Синтаксис выглядит следующим образом:

КритерийОтбора.СвязанныеДокументы(&ЗначениеКритерияОтбора)

В платформе 1С категорически запрещено передавать поле одной таблицы в качестве параметра виртуальной таблицы другой при соединении. Конструкция следующего вида синтаксически неверна и вызовет ошибку компиляции запроса:


// ВНИМАНИЕ: Данный запрос вызовет ошибку!
ВЫБРАТЬ
    Заказ.Ссылка,
    СвязанныеДокументы.Ссылка
ИЗ
    Документ.ЗаказКлиента КАК Заказ
    ЛЕВОЕ СОЕДИНЕНИЕ КритерийОтбора.СвязанныеДокументы(Заказ.Ссылка) КАК СвязанныеДокументы
        ПО Истина

Параметром виртуальной таблицы может выступать только внешняя переменная запроса (начинающаяся с символа &). Она едина для всего запроса, поэтому получить уникальные связанные документы индивидуально для каждой строки динамического списка в одном общем запросе через критерий отбора невозможно.

Выяснив причину ограничения, рассмотрим два практических способа обхода этой проблемы.

---

Решение 1: Прямое левое соединение таблиц документов (Direct JOIN)

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

Разберем по шагам, как настроить такой запрос для динамического списка документов Заказы, чтобы вытащить договор со статусом «Новый» из подчиненного документа Соглашение:

  1. Откроем форму списка документов Заказы.
  2. Перейдем в свойства реквизита формы Список (тип ДинамическийСписок).
  3. Установим флаг Произвольный запрос и откроем конструктор запроса.
  4. Вставим следующий текст запроса:

ВЫБРАТЬ
    ТаблицаЗаказы.Ссылка КАК Ссылка,
    ТаблицаЗаказы.ПометкаУдаления КАК ПометкаУдаления,
    ТаблицаЗаказы.Номер КАК Номер,
    ТаблицаЗаказы.Дата КАК Дата,
    ТаблицаЗаказы.Проведен КАК Проведен,
    ЕСТЬNULL(ТаблицаСоглашения.Договор, ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка)) КАК Договор
ИЗ
    Документ.ЗаказКлиента КАК ТаблицаЗаказы
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.Соглашение КАК ТаблицаСоглашения
        ПО ТаблицаСоглашения.ДокументОснование = ТаблицаЗаказы.Ссылка
        И ТаблицаСоглашения.Договор.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыДоговоров.Новый)

Анализ производительности данного решения:

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

При прокрутке (скроллинге) такого списка пользователем СУБД будет вынуждена "на лету" выполнять сложные соединения таблиц, что приведет к задержкам интерфейса (фризам) и повышению нагрузки на сервер.

---

Решение 2: Кэширование через служебный Регистр сведений (Рекомендованный стандарт 1С)

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

Рассмотрим этот вариант подробнее и разберем его реализацию по шагам.

Шаг 1. Создание метаданных

Создадим новый непериодический независимый регистр сведений СлужебныйДоговорыПоЗаказам со следующей структурой:

Шаг 2. Реализация логики записи (кэширования)

Заполнение регистра должно происходить автоматически при записи или проведении подчиненного документа (в нашем примере — Соглашения), а также при изменении статуса договора в нем. Запишем алгоритм в модуле подчиненного документа:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // Проверяем условия бизнес-логики: наличие договора и статус "Новый"
    Если ЗначениеЗаполнено(ЭтотОбъект.Договор) 
        И ЭтотОбъект.Договор.Статус = ПредопределенноеЗначение("Перечисление.СтатусыДоговоров.Новый") Тогда
        
        // Записываем связь в служебный регистр сведений
        МенеджерЗаписи = РегистрыСведений.СлужебныйДоговорыПоЗаказам.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.Заказ = ЭтотОбъект.ДокументОснование;
        МенеджерЗаписи.Договор = ЭтотОбъект.Договор;
        МенеджерЗаписи.Записать(Истина);
        
    КонецЕсли;

КонецПроцедуры

Процедура ПриКопировании(ОбъектКопирования)
    // Не забываем обрабатывать очистку или изменение связей при отмене проведения 
    // или пометке на удаление подчиненного документа.
КонецПроцедуры

Шаг 3. Использование кэша в динамическом списке

Теперь запрос динамического списка заказов становится максимально простым, а его скорость выполнения — молниеносной, так как СУБД делает выборку из одной заранее подготовленной физической таблицы регистра:


ВЫБРАТЬ
    ТаблицаЗаказы.Ссылка КАК Ссылка,
    ТаблицаЗаказы.Номер КАК Номер,
    ТаблицаЗаказы.Дата КАК Дата,
    ЕСТЬNULL(КэшДоговоров.Договор, ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка)) КАК Договор
ИЗ
    Документ.ЗаказКлиента КАК ТаблицаЗаказы
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СлужебныйДоговорыПоЗаказам КАК КэшДоговоров
        ПО КэшДоговоров.Заказ = ТаблицаЗаказы.Ссылка

Преимущества использования регистра-кэша:

---

Когда критерий отбора все-таки можно использовать как Основную таблицу?

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

Однако этот режим имеет строгую специфику применения:

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

← На главную