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