Как проверить соответствие объекта отбору СКД и вывести результат в таблицу значений

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

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

Постановка задачи и анализ ситуации

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

Решение 1: Программное создание СКД на основе запроса

Рассмотрим наиболее распространенный метод, основанный на динамическом формировании схемы компоновки данных. Этот метод хорош тем, что он универсален и позволяет использовать всю мощь языка запросов.

Шаг 1. Создание схемы и набора данных. Сначала нам нужно создать программный объект СхемаКомпоновкиДанных и добавить в него источник данных и набор данных (запрос).


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

Разберем процедуру копирования отбора. Поскольку ОтборКомпоновкиДанных может содержать как отдельные элементы, так и группы (И, ИЛИ, НЕ), необходимо обходить его иерархически.


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

Решение 2: Использование внешнего набора данных (Набор данных - Объект)

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

Рассмотрим, как изменить подход:

  1. Создадим схему, где вместо запроса используется НаборДанныхОбъектСхемыКомпоновкиДанных.
  2. В качестве источника данных передадим таблицу, содержащую одну строку с нашим объектом и всеми его реквизитами.
  3. СКД просто "наложит" фильтр на эту строку в памяти.

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

Важные нюансы реализации

При работе с программным выводом в таблицу значений следует обратить внимание на следующие технические моменты:

1. Автозаполнение полей. В первом сообщении темы автор пытался вручную перебирать колонки и добавлять поля в ТекущийНаборДанных.Поля. Это трудоемкий процесс, в котором легко ошибиться. Использование свойства АвтоЗаполнениеПолей = Истина позволяет системе самостоятельно определить доступные поля из текста запроса. Это критически важно, если пользователь в отборе захочет использовать реквизиты "через точку" (например, Склад.ТипСклада).

2. Генератор макета. Для вывода в ТЗ крайне важно использовать правильный тип генератора макета: ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений. Если использовать стандартный генератор для табличного документа, структура результата может быть искажена группировками.

3. Использование БСП. Если вы работаете в конфигурации на базе БСП (например, ERP, УТ 11 или КА), стоит проверить наличие типовых функций. Рассмотрим программный интерфейс общего модуля КомпоновкаДанныхКлиентСервер. Часто там уже реализованы методы для установки отборов и инициализации компоновщика, что позволяет сократить ваш код в несколько раз.

4. Оптимизация запроса. Если нам нужно просто проверить факт соответствия, в секции ВЫБРАТЬ достаточно указать только Ссылка или даже константу (например, 1 КАК Поле). Выбирать все поля через * не рекомендуется, так как это увеличивает нагрузку на систему при формировании макета.

Типичные ошибки

Проанализируем причины, по которым ТЗ может оставаться пустой, даже если объект должен проходить отбор:

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

← На главную