При разработке интерфейсов в «1С:Предприятие» часто возникает задача предоставить пользователю возможность фильтрации данных в динамических таблицах. Если источником данных для табличного поля выступает стандартный запрос к базе данных, платформа автоматически позволяет раскрывать ссылочные поля (например, Номенклатура) «через точку» и строить отборы по их вложенным свойствам (Артикул, Код, Производитель и т.д.).
Однако ситуация кардинально меняется, когда в качестве источника данных мы используем локальную ТаблицаЗначений, передаваемую в ПостроительЗапроса или ПостроительОтчета. В этом случае кнопка «Использовать дочерние» в интерфейсе настройки отборов становится недоступной, а пользователь теряет возможность накладывать условия на подчиненные реквизиты. Выясним причину этого ограничения и разберем по шагам три эффективных способа его обхода.
Когда данные выбираются напрямую из базы данных, платформа 1С заранее знает схему метаданных и связи между таблицами. Но как только мы передаем в построитель изолированную таблицу значений, находящуюся в оперативной памяти, эта связь теряется. Для построителя колонка с типом СправочникСсылка.Номенклатура становится просто набором ссылочных идентификаторов. Платформа «не догадывается», что у этих объектов в базе данных есть сопутствующие реквизиты, так как сама таблица в памяти этих реквизитов не содержит.
Для решения этой проблемы нам необходимо явно «подсказать» платформе структуру связей или использовать альтернативные механизмы компоновки. Рассмотрим подробнее каждый из рабочих методов.
Этот способ идеально подходит, если мы продолжаем использовать ПостроительЗапроса на основе таблицы значений, но хотим вручную связать дополнительные колонки с родительским объектом. Мы можем программно добавить в таблицу значений вспомогательные колонки под нужные реквизиты и настроить их позиционирование в дереве отбора.
Разберем реализацию этого метода по шагам:
Произвольный) в принципе не поддерживают отборы.НоменклатураАртикул).ПутьКДанным в объекте ОписаниеИсточникаДанных.Посмотрим на пример программной реализации:
// 1. Создаем типизированную таблицу значений
ТаблицаДанных = Новый ТаблицаЗначений;
// Описываем типы для колонок
МассивТиповНоменклатура = Новый Массив;
МассивТиповНоменклатура.Добавить(Тип("СправочникСсылка.Номенклатура"));
ОписаниеТиповНоменклатура = Новый ОписаниеТипов(МассивТиповНоменклатура);
МассивТиповСтрока = Новый Массив;
МассивТиповСтрока.Добавить(Тип("Строка"));
ОписаниеТиповСтрока = Новый ОписаниеТипов(МассивТиповСтрока, , Новый КвалификаторыСтроки(100));
// Добавляем основные и вспомогательные колонки
ТаблицаДанных.Колонки.Добавить("Номенклатура", ОписаниеТиповНоменклатура);
ТаблицаДанных.Колонки.Добавить("НоменклатураАртикул", ОписаниеТиповСтрока);
// Заполняем таблицу данными (для примера)
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("00001");
НоваяСтрока.НоменклатураАртикул = НоваяСтрока.Номенклатура.Артикул;
// 2. Настраиваем ОписаниеИсточникаДанных для построителя
Источник = Новый ОписаниеИсточникаДанных(ТаблицаДанных);
// Указываем путь к данным "через точку"
Источник.Колонки.НоменклатураАртикул.ПутьКДанным = "Номенклатура.Артикул";
Источник.Колонки.НоменклатураАртикул.Представление = "Артикул";
// Передаем источник в построитель запроса
ПостроительЗапроса = Новый ПостроительЗапроса;
ПостроительЗапроса.ИсточникДанных = Источник;
ПостроительЗапроса.ЗаполнитьНастройки();
После выполнения этого кода в интерфейсе настройки отборов колонка НоменклатураАртикул визуально превратится в дочернее поле Артикул внутри ветки Номенклатура. Пользователь сможет работать с ней так же, как и со стандартными реквизитами БД.
Существует элегантный обходной путь, позволяющий обмануть ПостроительЗапроса на этапе настройки интерфейса. Мы заставляем систему думать, что она работает с реальной таблицей базы данных, а перед непосредственным выполнением запроса подменяем схему на нашу таблицу значений.
Проанализируем этот алгоритм:
Номенклатура.Родитель.Код).Посмотрим на пример реализации данного лайфхака:
// Шаг 1. Задаем фиктивный запрос для инициализации метаданных в построителе
Построитель.Текст =
"ВЫБРАТЬ
| ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) КАК Номенклатура
|ПОМЕСТИТЬ ВТ_Данные";
Построитель.ЗаполнитьНастройки();
// Теперь в интерфейсе пользователю доступны все подчиненные поля Номенклатуры
// ... Ожидаем, пока пользователь настроит необходимые отборы на форме ...
// Шаг 2. Получаем запрос с учетом пользовательских отборов
СформированныйЗапрос = Построитель.ПолучитьЗапрос();
// Шаг 3. Динамически подменяем фиктивную временную таблицу на реальный источник
СформированныйЗапрос.Текст = СтрЗаменить(
СформированныйЗапрос.Текст,
"ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) КАК Номенклатура ПОМЕСТИТЬ ВТ_Данные",
"&ВнешняяТЗ КАК ТЗ"
);
// Передаем нашу реальную таблицу значений в параметры запроса
СформированныйЗапрос.УстановитьПараметр("ВнешняяТЗ", МояИсходнаяТаблицаЗначений);
// Выполняем запрос и выгружаем отфильтрованные данные
РезультатФильтрации = СформированныйЗапрос.Выполнить().Выгрузить();
Этот способ позволяет избежать ручного прописывания каждого дочернего реквизита в коде и предоставляет пользователю неограниченную свободу при работе со ссылочными полями.
Наиболее современным, надежным и гибким решением является использование Системы компоновки данных (СКД). Компоновщик настроек изначально проектировался с расчетом на работу со сложными типами данных. Даже при передаче внешней таблицы значений СКД корректно определяет структуру объектов, если мы жестко укажем типы полей в схеме компоновки.
Разберем по шагам, как это реализовать:
ИмяВнешнейТЗ).Номенклатура и в колонке Тип значения обязательно прописываем конкретный тип: СправочникСсылка.Номенклатура. Это ключевой момент, благодаря которому СКД поймет, какие дочерние поля существуют у объекта.КомпоновщикНастроек.Настройки.Отбор.Пример программной инициализации СКД перед выводом данных:
// Создаем структуру для передачи внешних наборов данных
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ИмяВнешнейТЗ", МояТаблицаЗначений);
// Инициализируем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(
СхемаКомпоновкиДанных,
КомпоновщикНастроек.ПолучитьНастройки()
);
// Проводим компоновку данных с передачей таблицы значений
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);
// Выгружаем результат в коллекцию или выводим в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
КонечнаяТаблица = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(КонечнаяТаблица);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Преимущество метода СКД: Полная поддержка платформенных механизмов. Платформа самостоятельно, без написания костылей и подмен текстов запросов, развернет дерево доступных полей для отбора и позволит накладывать условия любой вложенности.
Мы рассмотрели три эффективных подхода для обхода ограничений платформы 1С при работе с отборами по таблицам значений. Для простых интерфейсов Обычных форм отлично подойдет Способ 1 (переопределение ПутьКДанным) или Способ 2 (фиктивный запрос). При проектировании современных решений на Управляемых формах наиболее надежным стандартом является использование Способа 3 с внешними наборами данных СКД.