В практике разработчика 1С часто возникает задача создания универсальных инструментов для анализа данных. Одной из таких задач является построение запроса, который мог бы извлекать информацию (например, наименование или код) из любого справочника, выбранного пользователем на форме. В этой статье мы подробно разберем, как реализовать такой механизм, обсудим ограничения языка запросов и научимся безопасно работать с метаданными.
Для начала проанализируем важный технический нюанс. В языке запросов 1С нельзя передать имя таблицы (справочника, документа или регистра) через параметр. Попытка написать код типа Запрос.УстановитьПараметр("ТвояТаблица", "Номенклатура") приведет к ошибке. Имена таблиц должны быть жестко прописаны в тексте запроса до его компиляции.
Чтобы обойти это ограничение, мы будем использовать метод динамической сборки строки текста запроса. Рассмотрим простейший пример, когда у нас уже есть имя справочника в переменной ВидСправочника.
// Пример простой сборки текста запроса
ТекстЗапроса = "ВЫБРАТЬ
| Таблица.Ссылка КАК Ссылка,
| Таблица.Наименование КАК Наименование
|ИЗ
| Справочник." + ВидСправочника + " КАК Таблица";
Запрос = Новый Запрос(ТекстЗапроса);
Результат = Запрос.Выполнить();
В данном случае мы используем обычную конкатенацию строк. Переменная ВидСправочника должна содержать строковое имя объекта метаданных (например, "Контрагенты" или "Номенклатура").
Иногда требуется собрать данные не из одного конкретного справочника, а сразу из всех существующих в конфигурации. Для этого нам необходимо обратиться к коллекции Метаданные. Разберем по шагам, как сформировать массивный запрос, объединяющий данные всех справочников.
Рассмотрим алгоритм формирования текста запроса с использованием оператора ОБЪЕДИНИТЬ ВСЕ:
ШаблонЗапроса = "
|ВЫБРАТЬ
| ""#ИмяСправочника"" КАК ТипОбъекта,
| Таблица.Ссылка КАК Ссылка,
| Таблица.Наименование КАК Наименование
|ИЗ
| Справочник.#ИмяСправочника КАК Таблица";
ТекстЗапроса = "";
Для каждого ТекДанные из Метаданные.Справочники Цикл
// Проверяем, не пустой ли текст запроса, чтобы добавить объединение
Если Не ПустаяСтрока(ТекстЗапроса) Тогда
ТекстЗапроса = ТекстЗапроса + "
|ОБЪЕДИНИТЬ ВСЕ
|";
КонецЕсли;
// Подставляем реальное имя справочника в шаблон
ТекстЗапроса = ТекстЗапроса + СтрЗаменить(ШаблонЗапроса, "#ИмяСправочника", ТекДанные.Имя);
КонецЦикла;
Запрос = Новый Запрос(ТекстЗапроса);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.ТипОбъекта + ": " + Выборка.Наименование);
КонецЦикла;
Важное замечание: такой подход может существенно замедлить систему, если в базе данных сотни справочников и миллионы записей. Для глобального поиска по всей базе лучше использовать механизмы полнотекстового поиска 1С.
При написании универсальных запросов мы можем столкнуться с проблемой отсутствия определенных реквизитов. Например, автор темы упоминал реквизит НаименованиеПолное. В отличие от стандартного Наименование, этот реквизит создается разработчиком вручную и может отсутствовать в некоторых справочниках.
Выясним, как проверить наличие реквизита перед включением его в запрос, чтобы избежать критических ошибок:
ИмяСправочника = "Контрагенты"; // Имя может быть получено из формы
ИмяРеквизита = "НаименованиеПолное";
// Проверяем наличие реквизита в метаданных
Если Метаданные.Справочники[ИмяСправочника].Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
ПолеЗапроса = "Таблица." + ИмяРеквизита;
Иначе
// Если реквизита нет, выберем пустую строку или стандартное наименование
ПолеЗапроса = "Таблица.Наименование";
КонецЕсли;
ТекстЗапроса = "ВЫБРАТЬ " + ПолеЗапроса + " КАК Результат ИЗ Справочник." + ИмяСправочника + " КАК Таблица";
Этот метод позволяет создавать действительно гибкие инструменты, которые подстраиваются под структуру конкретного объекта метаданных.
Чтобы пользователь мог выбрать справочник на форме, не вводя его имя вручную (что чревато опечатками), мы можем программно заполнить список выбора. Рассмотрим два способа реализации этой задачи.
Способ 1: Использование списка значений. Мы перебираем метаданные и заполняем список, где значением будет техническое имя, а представлением — синоним (понятное пользователю название).
Для каждого Спр из Метаданные.Справочники Цикл
ЭлементыФормы.ВыборСправочника.СписокВыбора.Добавить(Спр.Имя, Спр.Синоним);
КонецЦикла;
Способ 2: Использование типа "ОписаниеТипов". На форме можно разместить реквизит с типом ОписаниеТипов и в свойствах ограничить его только справочниками. Тогда 1С сама предоставит стандартное окно выбора объектов метаданных.
При работе с универсальными запросами нельзя забывать о безопасности данных. В системе 1С может быть настроено ограничение доступа на уровне записей (RLS). Если у пользователя нет прав на чтение конкретного справочника, запрос выдаст ошибку.
Для предотвращения таких ситуаций всегда используйте ключевое слово РАЗРЕШЕННЫЕ. Проанализируем пример:
Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ Ссылка ИЗ Справочник." + ВыбранноеИмя;
Использование этого слова заставит систему просто игнорировать те записи и таблицы, на которые у текущего пользователя нет прав, вместо того чтобы прерывать выполнение программы.
Если вам не требуется сложная фильтрация или соединение таблиц, а нужно просто получить список всех элементов справочника, можно воспользоваться менеджером справочника. Это работает быстрее в написании и зачастую читабельнее для простых задач.
// Получаем выборку всех элементов выбранного справочника
ИмяСправочника = "Склады";
Выборка = Справочники[ИмяСправочника].Выбрать();
Пока Выборка.Следующий() Цикл
// Работаем с данными напрямую
Сообщить(Выборка.Наименование);
КонецЦикла;
Этот метод Справочники[ИмяСправочника] является крайне мощным инструментом, так как позволяет обращаться к любому менеджеру объекта по его строковому имени, полученному в процессе работы программы.
Мы рассмотрели несколько подходов к созданию универсальных запросов. Подведем итог:
ВЫБРАТЬ РАЗРЕШЕННЫЕ.Эти методы помогут вам создавать гибкие и надежные обработки для любых конфигураций на платформе 1С:Предприятие 8.