При интеграции различных баз данных 1С (например, через COM-соединение или при обращении к узлам распределенной информационной базы с несинхронными релизами) разработчики часто сталкиваются с ситуацией, когда состав реквизитов объектов различается. Возникает закономерный вопрос: можно ли прямо внутри текста запроса проверить, существует ли определенный реквизит, и если да — применить по нему отбор?
Разберем детально, почему платформа 1С накладывает фундаментальные ограничения на подобные операции в языке запросов, и рассмотрим корректные подходы к решению этой задачи.
Проверить существование реквизита непосредственно в тексте запроса с помощью стандартных операторов невозможно. Язык запросов 1С транслируется в SQL на этапе выполнения, а транслятор платформы выполняет строгую валидацию метаданных перед компиляцией запроса.
Важные особенности поведения платформы:
ВЫБРАТЬ или в условии ГДЕ указать имя поля, которого физически нет в метаданных конфигурации, платформа моментально вернет критическую синтаксическую ошибку «Поле не найдено» еще до фактического обращения к СУБД. Конструкции вида ВЫБОР КОГДА ... ЕСТЬ NULL или попытка проверки на пустое значение здесь не помогут.РАЗРЕШЕННЫЕ отвечает только за ограничение прав доступа на уровне записей (RLS). Оно исключает из результата те строки или поля, на которые у текущей роли нет прав, но не скрывает отсутствие самого реквизита в структуре конфигурации.Единственный надежный подход — выполнять проверку структуры объекта до выполнения запроса и динамически формировать текст либо параметры выборки.
Наиболее правильным, быстрым и безопасным решением является проверка наличия реквизита через глобальный объект Метаданные. Этот способ отлично работает как в текущей информационной базе, так и при подключении через внешнее соединение (COM).
Посмотрим на пример кода при работе с внешней базой через COM-соединение:
// Предположим, что внешнее соединение уже установлено в переменную COMСоединение
ИмяСправочника = "Номенклатура";
ИмяРеквизита = "АртикулПоставщика";
МетаданныеСправочника = COMСоединение.Метаданные.Справочники[ИмяСправочника];
// Проверяем наличие пользовательского реквизита
РеквизитСуществует = (МетаданныеСправочника.Реквизиты.Найти(ИмяРеквизита) <> Неопределено);
// Если реквизит может быть стандартным (например, Наименование, Код, Родитель)
Если Не РеквизитСуществует Тогда
РеквизитСуществует = (МетаданныеСправочника.СтандартныеРеквизиты.Найти(ИмяРеквизита) <> Неопределено);
КонецЕсли;
// Динамически формируем текст запроса в зависимости от результата
ТекстЗапроса =
"ВЫБРАТЬ
| Ссылка,
| Наименование
|ИЗ
| Справочник." + ИмяСправочника + " КАК Таблица";
Если РеквизитСуществует Тогда
ТекстЗапроса = ТекстЗапроса + "
|ГДЕ
| Таблица." + ИмяРеквизита + " = &ЗначениеОтбора";
КонецЕсли;
Запрос = COMСоединение.NewObject("Запрос");
Запрос.Текст = ТекстЗапроса;
Если РеквизитСуществует Тогда
Запрос.УстановитьПараметр("ЗначениеОтбора", ИскомоеЗначение);
КонецЕсли;
Выборка = Запрос.Выполнить().Выбрать();
Преимущества подхода: обращение к коллекции метаданных происходит в оперативной памяти без считывания данных таблиц СУБД, что исключает возникновение исключений и минимизирует задержки.
Если логика формирования запросов объемная и содержит множество условий, динамическая конкатенация строк может стать источником ошибок. Для таких задач платформой предусмотрен объект СхемаЗапроса, позволяющий программно манипулировать структурой запроса (добавлять источники, поля и условия отбора).
Разберем по шагам, как модифицировать условие с помощью схемы:
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(
"ВЫБРАТЬ
| Спр.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Спр"
);
// Если проверка метаданных подтвердила наличие реквизита
Если РеквизитСуществует Тогда
ОператорВыбора = Схема.ПакетЗапросов[0].Операторы[0];
// Добавляем условие отбора
ОператорВыбора.Отбор.Добавить("Спр.АртикулПоставщика = &ЗначениеОтбора");
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = Схема.ПолучитьТекстЗапроса();
Если РеквизитСуществует Тогда
Запрос.УстановитьПараметр("ЗначениеОтбора", ИскомоеЗначение);
КонецЕсли;
Результат = Запрос.Выполнить();
В универсальных процедурах, когда тип объекта заранее неизвестен или работа идет с прикладными объектами без прямого обращения к ветке метаданных, можно использовать метод ЗаполнитьЗначенияСвойств с проверкой маркерного значения.
Посмотрим на пример такого алгоритма:
Маркер = "_НЕСУЩЕСТВУЮЩЕЕ_ЗНАЧЕНИЕ_";
ИмяРеквизита = "ДополнительноеПоле";
Зонд = Новый Структура(ИмяРеквизита, Маркер);
ЗаполнитьЗначенияСвойств(Зонд, ПроверяемыйОбъект, ИмяРеквизита);
РеквизитЕсть = (Зонд[ИмяРеквизита] <> Маркер);
Этот метод подходит для объектов и структур данных, однако для подготовки запросов по базе данных проверка через Метаданные остается более прозрачной и производительной.
EnterpriseData), где изменение структуры реквизитов не нарушает работоспособность базового API.