Как программно изменить тип поля набора данных в СКД для корректной работы отборов?

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

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

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

Почему возникает проблема с отборами?

Разберем ситуацию глубже. Когда 1С инициализирует отчет, КомпоновщикНастроек анализирует схему компоновки данных. Если в тексте запроса указано 0 КАК Поле, СКД жестко фиксирует тип этого поля как Число. Даже если позже, в процедуре ПриКомпоновкеРезультата, вы подмените текст запроса на реальный, визуальная часть (формы настроек) уже будет построена на основании исходных данных о типах. В результате в окне выбора значения для отбора система будет предлагать ввод числа, а не список элементов справочника.

Решение 1: Программное переопределение типа в модуле объекта

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

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


// В модуле объекта отчета
Схема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
НаборДанных = Схема.НаборыДанных.НаборДанных1; // Укажите имя вашего набора
ПолеНужныйСправочник = НаборДанных.Поля.Найти("НужныйСправочник");

Если ПолеНужныйСправочник <> Неопределено Тогда
    // Программное назначение типа из расширения
    ПолеНужныйСправочник.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.НужныйСправочник");
КонецЕсли;

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

Решение 2: Использование события ПередЗагрузкойВарианта

Хотя размещение кода «вне процедур» работает, более правильным с точки зрения архитектуры 1С считается использование специализированных обработчиков событий. Мы можем использовать обработчик ПередЗагрузкойВарианта в модуле объекта отчета.

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

  1. Перейдем в модуль объекта отчета.
  2. Создадим процедуру-обработчик ПередЗагрузкойВариантаНаСервере (или используем стандартные события модуля).
  3. Выполним переопределение схемы и, что критически важно, обновим Источник доступных настроек.

Процедура ПередЗагрузкойВарианта(Настройки)
    
    // Получаем схему
    Схема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    
    // Меняем тип поля
    Поле = Схема.НаборыДанных.НаборДанных1.Поля.Найти("НужныйСправочник");
    Если Поле <> Неопределено Тогда
        Поле.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.ИмяСправочникаИзРасширения");
    КонецЕсли;
    
    // Обновляем текст запроса, если это необходимо
    Схема.НаборыДанных.НаборДанных1.Запрос = "ВЫБРАТЬ Ссылка КАК НужныйСправочник ИЗ Справочник.ИмяСправочникаИзРасширения";
    
    // Переинициализируем компоновщик, чтобы он увидел изменения в типах
    ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема);
    КомпоновщикНастроек.Инициализировать(ИсточникНастроек);
    
КонецПроцедуры

Решение 3: Улучшенная заглушка в запросе через ВЫРАЗИТЬ

Выясним причину, по которой 0 КАК Поле работает хуже, чем другие варианты. Если мы используем просто ноль, СКД не имеет ни малейшего шанса угадать тип. Однако мы можем помочь системе, даже если объект находится в расширении, используя типизацию на уровне самого запроса-заглушки. Это позволит избежать части программного кода.

Вместо 0 КАК НужныйСправочник попробуем использовать конструкцию:


ВЫБРАТЬ
    ВЫРАЗИТЬ(NULL КАК Справочник.ИмяСправочникаИзРасширения) КАК НужныйСправочник
ИЗ
    Справочник.ЛюбойДоступныйСправочник КАК Справочник
ГДЕ
    ЛОЖЬ

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

Решение 4: Программная установка отбора

Если нам не удается изменить тип самого поля (например, в сложных динамических наборах данных), мы можем пойти путем принудительной установки элемента отбора с нужным типом значения. Рассмотрим пример кода, который программно добавляет элемент отбора в компоновщик настроек:


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

// Устанавливаем пустую ссылку нужного типа для инициализации выбора
ЭлементОтбора.ПравоеЗначение = ПредопределенноеЗначение("Справочник.ИмяСправочникаИзРасширения.ПустаяСсылка");

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

Рекомендации по работе с внешними отчетами и расширениями

Подводя итог, проанализируем лучшие практики для таких задач:

Рассмотрим, как добавить вычисляемое поле программно:


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

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

← На главную