Как настроить отбор по дочерним реквизитам в табличном поле для Таблицы Значений

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

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

Однако ситуация кардинально меняется, когда в качестве источника данных мы используем локальную ТаблицаЗначений, передаваемую в ПостроительЗапроса или ПостроительОтчета. В этом случае кнопка «Использовать дочерние» в интерфейсе настройки отборов становится недоступной, а пользователь теряет возможность накладывать условия на подчиненные реквизиты. Выясним причину этого ограничения и разберем по шагам три эффективных способа его обхода.

Почему возникает проблема: анализируем архитектуру платформы

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

Для решения этой проблемы нам необходимо явно «подсказать» платформе структуру связей или использовать альтернативные механизмы компоновки. Рассмотрим подробнее каждый из рабочих методов.


Способ 1. Использование свойства «ПутьКДанным» в описании источника

Этот способ идеально подходит, если мы продолжаем использовать ПостроительЗапроса на основе таблицы значений, но хотим вручную связать дополнительные колонки с родительским объектом. Мы можем программно добавить в таблицу значений вспомогательные колонки под нужные реквизиты и настроить их позиционирование в дереве отбора.

Разберем реализацию этого метода по шагам:

  1. Создаем исходную таблицу значений и явно типизируем колонки. Это критически важно, так как нетипизированные колонки (с типом Произвольный) в принципе не поддерживают отборы.
  2. Добавляем в таблицу значений колонку для хранения подчиненного реквизита (например, НоменклатураАртикул).
  3. При заполнении таблицы значений записываем в эту колонку реальные артикулы.
  4. Связываем колонку с основным полем через свойство ПутьКДанным в объекте ОписаниеИсточникаДанных.

Посмотрим на пример программной реализации:


// 1. Создаем типизированную таблицу значений
ТаблицаДанных = Новый ТаблицаЗначений;

// Описываем типы для колонок
МассивТиповНоменклатура = Новый Массив;
МассивТиповНоменклатура.Добавить(Тип("СправочникСсылка.Номенклатура"));
ОписаниеТиповНоменклатура = Новый ОписаниеТипов(МассивТиповНоменклатура);

МассивТиповСтрока = Новый Массив;
МассивТиповСтрока.Добавить(Тип("Строка"));
ОписаниеТиповСтрока = Новый ОписаниеТипов(МассивТиповСтрока, , Новый КвалификаторыСтроки(100));

// Добавляем основные и вспомогательные колонки
ТаблицаДанных.Колонки.Добавить("Номенклатура", ОписаниеТиповНоменклатура);
ТаблицаДанных.Колонки.Добавить("НоменклатураАртикул", ОписаниеТиповСтрока);

// Заполняем таблицу данными (для примера)
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("00001");
НоваяСтрока.НоменклатураАртикул = НоваяСтрока.Номенклатура.Артикул;

// 2. Настраиваем ОписаниеИсточникаДанных для построителя
Источник = Новый ОписаниеИсточникаДанных(ТаблицаДанных);

// Указываем путь к данным "через точку"
Источник.Колонки.НоменклатураАртикул.ПутьКДанным = "Номенклатура.Артикул";
Источник.Колонки.НоменклатураАртикул.Представление = "Артикул";

// Передаем источник в построитель запроса
ПостроительЗапроса = Новый ПостроительЗапроса;
ПостроительЗапроса.ИсточникДанных = Источник;
ПостроительЗапроса.ЗаполнитьНастройки();

После выполнения этого кода в интерфейсе настройки отборов колонка НоменклатураАртикул визуально превратится в дочернее поле Артикул внутри ветки Номенклатура. Пользователь сможет работать с ней так же, как и со стандартными реквизитами БД.


Способ 2. Лайфхак с виртуальным «фиктивным» запросом

Существует элегантный обходной путь, позволяющий обмануть ПостроительЗапроса на этапе настройки интерфейса. Мы заставляем систему думать, что она работает с реальной таблицей базы данных, а перед непосредственным выполнением запроса подменяем схему на нашу таблицу значений.

Проанализируем этот алгоритм:

  1. Инициализируем построитель текста запроса, в котором обращаемся к реальной таблице метаданных, но выбираем пустую ссылку. Благодаря этому действию построитель считывает полную структуру метаданных справочника, и кнопка «Использовать дочерние» становится активной.
  2. Выводим настройки отбора пользователю на форму. Пользователь интерактивно настраивает любые сложные отборы через точку (например, по реквизиту Номенклатура.Родитель.Код).
  3. Перед формированием отчета программно перехватываем настроенный построителем текст запроса и заменяем источник данных на реальный параметр с нашей таблицей значений.

Посмотрим на пример реализации данного лайфхака:


// Шаг 1. Задаем фиктивный запрос для инициализации метаданных в построителе
Построитель.Текст = 
    "ВЫБРАТЬ
    |    ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) КАК Номенклатура
    |ПОМЕСТИТЬ ВТ_Данные";

Построитель.ЗаполнитьНастройки();
// Теперь в интерфейсе пользователю доступны все подчиненные поля Номенклатуры

// ... Ожидаем, пока пользователь настроит необходимые отборы на форме ...

// Шаг 2. Получаем запрос с учетом пользовательских отборов
СформированныйЗапрос = Построитель.ПолучитьЗапрос();

// Шаг 3. Динамически подменяем фиктивную временную таблицу на реальный источник
СформированныйЗапрос.Текст = СтрЗаменить(
    СформированныйЗапрос.Текст, 
    "ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) КАК Номенклатура ПОМЕСТИТЬ ВТ_Данные", 
    "&ВнешняяТЗ КАК ТЗ"
);

// Передаем нашу реальную таблицу значений в параметры запроса
СформированныйЗапрос.УстановитьПараметр("ВнешняяТЗ", МояИсходнаяТаблицаЗначений);

// Выполняем запрос и выгружаем отфильтрованные данные
РезультатФильтрации = СформированныйЗапрос.Выполнить().Выгрузить();

Этот способ позволяет избежать ручного прописывания каждого дочернего реквизита в коде и предоставляет пользователю неограниченную свободу при работе со ссылочными полями.


Способ 3. Переход на СКД через внешний набор данных (рекомендуемый)

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

Разберем по шагам, как это реализовать:

  1. Создаем схему компоновки данных (программно или в макете).
  2. Добавляем в схему Набор данных - объект и указываем имя источника (например, ИмяВнешнейТЗ).
  3. Добавляем поле набора данных Номенклатура и в колонке Тип значения обязательно прописываем конкретный тип: СправочникСсылка.Номенклатура. Это ключевой момент, благодаря которому СКД поймет, какие дочерние поля существуют у объекта.
  4. Выводим настройки отбора компоновщика на форму в качестве табличного поля, связав его с путем к данным КомпоновщикНастроек.Настройки.Отбор.

Пример программной инициализации СКД перед выводом данных:


// Создаем структуру для передачи внешних наборов данных
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ИмяВнешнейТЗ", МояТаблицаЗначений);

// Инициализируем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(
    СхемаКомпоновкиДанных, 
    КомпоновщикНастроек.ПолучитьНастройки()
);

// Проводим компоновку данных с передачей таблицы значений
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);

// Выгружаем результат в коллекцию или выводим в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
КонечнаяТаблица = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(КонечнаяТаблица);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

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


Резюме

Мы рассмотрели три эффективных подхода для обхода ограничений платформы 1С при работе с отборами по таблицам значений. Для простых интерфейсов Обычных форм отлично подойдет Способ 1 (переопределение ПутьКДанным) или Способ 2 (фиктивный запрос). При проектировании современных решений на Управляемых формах наиболее надежным стандартом является использование Способа 3 с внешними наборами данных СКД.

← На главную