При разработке сложных универсальных отчетов, обработок закрытия периодов или инструментов для выборочного удаления данных в 1С программисты часто сталкиваются с необходимостью программного формирования Схемы компоновки данных (СКД). Одним из частых сценариев является добавление в запрос СКД различных служебных или вспомогательных полей (например, ДопПоле), которые требуются разработчику для дальнейших программных расчетов, вычисления ресурсов или постобработки полученного результата. Однако эти служебные поля абсолютно не нужны конечному пользователю в списке доступных полей выбора, группировок, сортировки и, самое главное, в доступных полях отбора.
Ситуация осложняется, когда в программно создаваемом наборе данных СКД используется свойство АвтоЗаполнениеДоступныхПолей = Истина. При включенном автозаполнении платформа 1С автоматически сканирует текст запроса и вытягивает все доступные поля в компоновщик настроек. В этой статье мы подробно разберем, как перехватить этот процесс, правильно установить ограничения на использование полей и скрыть служебные данные от глаз пользователей, сохранив при этом возможность работать с ними в коде.
Давайте проанализируем типичный алгоритм программного создания СКД, который приводит к проблеме. Обычно разработчик пишет следующий код:
СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
ИсточникДанных.Имя = "ИсточникДанных1";
ИсточникДанных.ТипИсточникаДанных = "local";
НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
НаборДанных.ИсточникДанных = "ИсточникДанных1";
НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
НаборДанных.Запрос = ТекстЗапроса; // Текст запроса содержит "ВЫБРАТЬ ..., СлужебноеПоле КАК ДопПоле ИЗ ..."
НаборДанных.Имя = "НаборДанных1";
АдресСхемы = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных, УникальныйИдентификатор);
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы));
Если мы попытаемся обратиться к коллекции НаборДанных.Поля до момента вызова метода Инициализировать() у объекта КомпоновщикНастроек, мы обнаружим, что эта коллекция абсолютно пуста! На первый взгляд кажется, что автозаполнение полей происходит «где-то внутри» платформы в момент инициализации компоновщика, и повлиять на состав полей или наложить на них ограничения программно невозможно.
Попытка настроить ограничения непосредственно в компоновщике настроек после инициализации также обречена на провал, поскольку свойства доступных полей компоновщика (такие как ДоступныеПоляВыбора, ДоступныеПоляОтбора) доступны только для чтения и формируются динамически на основе переданной схемы.
Выясним, как элегантно обойти это ограничение платформы.
Для решения задачи нам нужно воспользоваться важной особенностью объектной модели СКД. Когда у набора данных включено свойство АвтоЗаполнениеДоступныхПолей = Истина, платформа 1С при разборе запроса проверяет, объявлены ли какие-либо поля в коллекции НаборДанных.Поля вручную. Если поле с аналогичным именем (или путем к данным) уже добавлено в схему программным путем, то платформа не создает его дубликат. Вместо этого она берет за основу ваше программно созданное поле и накладывает на него логику автозаполнения, сохраняя при этом все заданные вами вручную настройки (заголовки, типы, а также флаги ограничений использования).
Таким образом, нам достаточно до помещения схемы во временное хранилище и до инициализации компоновщика принудительно добавить наше ДопПоле в коллекцию НаборДанных.Поля и явно прописать для него требуемые ограничения.
Рассмотрим по шагам реализацию этого подхода на примере кода:
// Шаг 1. Создаем схему и источник данных
СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
ИсточникДанных.Имя = "ИсточникДанных1";
ИсточникДанных.ТипИсточникаДанных = "local";
// Шаг 2. Создаем набор данных - запрос
НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
НаборДанных.ИсточникДанных = "ИсточникДанных1";
НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
НаборДанных.Запрос = "ВЫБРАТЬ Данные.Ссылка КАК Ссылка, ""СлужебноеЗначение"" КАК ДопПоле ИЗ Справочник.Номенклатура КАК Данные";
НаборДанных.Имя = "НаборДанных1";
// Шаг 3. Программно добавляем наше ДопПоле в коллекцию полей набора данных ДО инициализации
НовоеПоле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
НовоеПоле.Поле = "ДопПоле"; // Имя поля в запросе
НовоеПоле.ПутьКДанным = "ДопПоле"; // Путь к данным в СКД
НовоеПоле.Заголовок = "Дополнительное поле (служебное)";
// Шаг 4. Устанавливаем ограничение использования для условий отбора
НовоеПоле.ОграничениеИспользования.Условие = Истина;
// Шаг 5. Инициализируем компоновщик настроек через временное хранилище
АдресСхемы = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных, Новый УникальныйИдентификатор);
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы));
В этом примере свойство ОграничениеИспользования.Условие = Истина сообщает системе компоновки данных о том, что данное поле категорически запрещено использовать при построении условий отбора (в секции ГДЕ запроса СКД и на вкладке «Отбор» пользовательских настроек). В результате поле пропадет из доступных полей отбора компоновщика настроек, но при этом СКД все так же будет без проблем выбирать его из базы данных для ваших внутренних алгоритмов.
Установки одного лишь ограничения на условия (Условие = Истина) часто бывает недостаточно. Пользователь все еще сможет увидеть это поле в списке доступных полей выбора, вывести его в колонки отчета, использовать для группировки строк или настроить по нему сортировку (порядок).
Если ваша задача — сделать поле абсолютно невидимым для пользователя во всех интерфейсах настройки отчета, то необходимо установить ограничения по всем возможным направлениям. Рассмотрим, как это сделать:
// Полный запрет на использование поля пользователем во всех элементах настроек СКД
НовоеПоле.ОграничениеИспользования.Условие = Истина; // Запрет использования в отборах
НовоеПоле.ОграничениеИспользования.Поле = Истина; // Запрет выбора в качестве выводимого поля
НовоеПоле.ОграничениеИспользования.Группировка = Истина; // Запрет использования в группировках
НовоеПоле.ОграничениеИспользования.Порядок = Истина; // Запрет сортировки по этому полю
Применение этой группы свойств полностью изолирует служебное поле от пользовательского интерфейса, сохраняя его работоспособность «под капотом» компоновщика.
Программное добавление полей в коллекцию схемы — отличный рабочий вариант, но он требует написания громоздкого кода для каждого скрываемого поля. Если таких служебных полей в вашем динамическом запросе много, есть более изящное и профессиональное решение, принятое в стандартах разработки фирмы «1С».
Это решение заключается в отказе от автозаполнения (АвтоЗаполнениеДоступныхПолей = Ложь) и явном описании доступных для настройки полей с помощью расширения языка запросов СКД (использования фигурных скобок).
Посмотрим на пример реализации такого подхода. Вместо того чтобы полагаться на автоматический разбор, мы пишем запрос следующим образом:
ТекстЗапроса =
"ВЫБРАТЬ
| Регистр.Номенклатура КАК Номенклатура,
| Регистр.Количество КАК Количество,
| ""СлужебныеДанные"" КАК ДопПоле
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК Регистр
|
|{ВЫБРАТЬ
| Номенклатура.*,
| Количество}
|{ГДЕ
| Номенклатура.*,
| Количество}";
При такой конструкции и установленном свойстве НаборДанных.АвтоЗаполнениеДоступныхПолей = Ложь СКД проанализирует только то, что написано внутри фигурных скобок {...}:
Номенклатура и Количество будут доступны пользователю для выбора, отборов и группировок, так как они явно объявлены в секциях {ВЫБРАТЬ} и {ГДЕ}.ДопПоле физически выберется основным запросом СУБД, однако оно полностью отсутствует в инструкциях расширения языка запросов СКД. Это значит, что СКД не добавит его в список доступных полей компоновщика настроек. Оно будет абсолютно невидимым для пользователя без написания какого-либо дополнительного программного кода ограничений.Этот метод считается более гибким и масштабируемым, особенно при работе со сложными запросами, содержащими виртуальные таблицы или многочисленные соединения.
Мы подробно разобрали два основных способа решения проблемы с нежелательными полями отбора при программном создании СКД:
АвтоЗаполнениеДоступныхПолей = Истина) и точечно ограничить видимость конкретных служебных полей. Для этого нужно программно добавить объект ПолеНабораДанныхСхемыКомпоновкиДанных в коллекцию до инициализации компоновщика настроек и установить свойства группы ОграничениеИспользования.