При разработке отчетов на базе Системы компоновки данных (СКД) часто возникает ситуация, когда отчет должен обращаться к объектам метаданных, находящимся в расширении. Если вы создаете внешний отчет или пытаетесь редактировать основную схему в конфигураторе, система может выдать ошибку, так как «не видит» объектов расширения. Стандартным обходным путем является создание запроса-заглушки, где вместо реальной ссылки используется конструкция вида 0 КАК НужныйСправочник. Однако это порождает новую проблему: СКД определяет тип поля как «Число», и в пользовательских настройках (отборах) невозможно выбрать элемент справочника.
В этой статье мы подробно разберем, как программно переопределить тип поля набора данных, чтобы механизмы отбора работали корректно, и пользователь мог выбирать значения из справочников расширения.
Разберем ситуацию глубже. Когда 1С инициализирует отчет, КомпоновщикНастроек анализирует схему компоновки данных. Если в тексте запроса указано 0 КАК Поле, СКД жестко фиксирует тип этого поля как Число. Даже если позже, в процедуре ПриКомпоновкеРезультата, вы подмените текст запроса на реальный, визуальная часть (формы настроек) уже будет построена на основании исходных данных о типах. В результате в окне выбора значения для отбора система будет предлагать ввод числа, а не список элементов справочника.
Проанализируем самый эффективный способ, найденный участниками обсуждения. Основная идея заключается в том, чтобы изменить свойство ТипЗначения у поля набора данных до того, как настройки будут окончательно применены в интерфейсе.
Рассмотрим пример кода, который необходимо разместить в модуле объекта отчета. Важным нюансом является место размещения кода. Как выяснилось в ходе дискуссии, размещение этого кода непосредственно в теле модуля (вне процедур) позволяет инициализировать типы при создании экземпляра объекта.
// В модуле объекта отчета
Схема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
НаборДанных = Схема.НаборыДанных.НаборДанных1; // Укажите имя вашего набора
ПолеНужныйСправочник = НаборДанных.Поля.Найти("НужныйСправочник");
Если ПолеНужныйСправочник <> Неопределено Тогда
// Программное назначение типа из расширения
ПолеНужныйСправочник.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.НужныйСправочник");
КонецЕсли;
При таком подходе, когда пользователь откроет отчет, Компоновщик настроек уже будет знать, что поле НужныйСправочник имеет тип ссылки, и предоставит соответствующий интерфейс выбора.
Хотя размещение кода «вне процедур» работает, более правильным с точки зрения архитектуры 1С считается использование специализированных обработчиков событий. Мы можем использовать обработчик ПередЗагрузкойВарианта в модуле объекта отчета.
Давайте посмотрим, как реализовать это по шагам:
ПередЗагрузкойВариантаНаСервере (или используем стандартные события модуля).
Процедура ПередЗагрузкойВарианта(Настройки)
// Получаем схему
Схема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
// Меняем тип поля
Поле = Схема.НаборыДанных.НаборДанных1.Поля.Найти("НужныйСправочник");
Если Поле <> Неопределено Тогда
Поле.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.ИмяСправочникаИзРасширения");
КонецЕсли;
// Обновляем текст запроса, если это необходимо
Схема.НаборыДанных.НаборДанных1.Запрос = "ВЫБРАТЬ Ссылка КАК НужныйСправочник ИЗ Справочник.ИмяСправочникаИзРасширения";
// Переинициализируем компоновщик, чтобы он увидел изменения в типах
ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема);
КомпоновщикНастроек.Инициализировать(ИсточникНастроек);
КонецПроцедуры
Выясним причину, по которой 0 КАК Поле работает хуже, чем другие варианты. Если мы используем просто ноль, СКД не имеет ни малейшего шанса угадать тип. Однако мы можем помочь системе, даже если объект находится в расширении, используя типизацию на уровне самого запроса-заглушки. Это позволит избежать части программного кода.
Вместо 0 КАК НужныйСправочник попробуем использовать конструкцию:
ВЫБРАТЬ
ВЫРАЗИТЬ(NULL КАК Справочник.ИмяСправочникаИзРасширения) КАК НужныйСправочник
ИЗ
Справочник.ЛюбойДоступныйСправочник КАК Справочник
ГДЕ
ЛОЖЬ
Важный момент: Конструктор схемы может подчеркивать такой запрос красным, если расширение не подключено к основной базе в процессе разработки, но при выполнении в системе, где расширение активно, этот код отработает корректно. СКД сразу получит информацию о типе поля из описания метаданных.
Если нам не удается изменить тип самого поля (например, в сложных динамических наборах данных), мы можем пойти путем принудительной установки элемента отбора с нужным типом значения. Рассмотрим пример кода, который программно добавляет элемент отбора в компоновщик настроек:
ЭлементОтбора = КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("НужныйСправочник");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.Использование = Ложь; // Пользователь сам включит, если нужно
// Устанавливаем пустую ссылку нужного типа для инициализации выбора
ЭлементОтбора.ПравоеЗначение = ПредопределенноеЗначение("Справочник.ИмяСправочникаИзРасширения.ПустаяСсылка");
Этот метод гарантирует, что в списке отборов появится поле, которое изначально будет предлагать выбор из нужного справочника, так как ПравоеЗначение уже типизировано ссылкой.
Подводя итог, проанализируем лучшие практики для таких задач:
Инициализировать у КомпоновщикаНастроек, передавая туда обновленную схему.Новый ОписаниеТипов для объектов из расширений, убедитесь, что имя типа указано точно так же, как оно задано в метаданных расширения.Рассмотрим, как добавить вычисляемое поле программно:
ВычисляемоеПоле = Схема.ВычисляемыеПоля.Добавить();
ВычисляемоеПоле.ПутьКДанным = "ПолеИзРасширения";
ВычисляемоеПоле.Выражение = "НужныйСправочник"; // Ссылка на поле из набора данных
ВычисляемоеПоле.Заголовок = "Справочник из расширения";
ВычисляемоеПоле.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.ИмяСправочникаИзРасширения");
Этот метод часто оказывается более стабильным, так как не затрагивает основную структуру запроса-заглушки и позволяет гибко управлять отображением данных для пользователя.