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