При разработке универсальных обработок, особенно для конфигураций со сложной структурой данных (таких как Управление торговлей 10.3 или ERP), мы часто сталкиваемся с необходимостью найти все поля, содержащие определенный тип данных. Например, при построении отчета или фильтрации данных по конкретной организации, нам нужно знать, в каких измерениях или реквизитах регистров хранится ссылка на СправочникСсылка.Организации (в сложных случаях поможет Analyzer 1C — инструмент для анализа зависимостей).
Поиск по имени реквизита (например, искать слово "Организация") — путь ненадежный. В типовых конфигурациях 1С часто используются универсальные имена полей, такие как Объект, Владелец или Субконто, которые технически содержат нужный нам тип, но не выдают себя названием. В этой статье мы разберем, как эффективно решать задачу поиска через механизмы Библиотеки Стандартных Подсистем (БСП) и собственные алгоритмы оптимизации.
В составе БСП существует готовый инструмент для решения нашей задачи. Чаще всего эта функция расположена в общем модуле ОбщегоНазначения. Однако важно учитывать, что реализация этой функции может отличаться в зависимости от версии БСП, установленной в вашей конфигурации.
Рассмотрим классический вариант реализации, который встречается в большинстве современных систем на базе 1С:Предприятие 8.3:
Функция ИменаРеквизитовПоТипу(МетаданныеОбъекта, Тип) Экспорт
ИменаРеквизитов = Новый Массив;
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
Если Реквизит.Тип.СодержитТип(Тип) Тогда
ИменаРеквизитов.Добавить(Реквизит.Имя);
КонецЕсли;
КонецЦикла;
Возврат ИменаРеквизитов;
КонецФункции
Проанализируем этот код. Функция принимает объект метаданных (визуализировать дерево которых поможет информер по метаданным) и искомый тип. Метод СодержитТип() позволяет корректно обрабатывать даже составные типы данных, что критически важно для универсальных механизмов.
При работе с разными конфигурациями (например, при переносе кода из УТ 10.3 в ERP) мы можем столкнуться с тем, что одна и та же функция возвращает разные типы данных. В старых версиях БСП функция могла возвращать строку с именами реквизитов, разделенными запятыми, а в новых — массив строк.
Чтобы наш код был по-настоящему универсальным, проанализируем ситуацию и внедрим проверку возвращаемого значения:
РезультатФункции = ОбщегоНазначения.ИменаРеквизитовПоТипу(МетаданныеОбъекта, ТипЗнч(НужнаяОрганизация));
Если ТипЗнч(РезультатФункции) = Тип("Массив") Тогда
МассивИмен = РезультатФункции;
ИначеЕсли ТипЗнч(РезультатФункции) = Тип("Строка") Тогда
МассивИмен = СтрРазделить(РезультатФункции, ", ", Ложь);
КонецЕсли;
Для Каждого ИмяПоля Из МассивИмен Цикл
// Обработка найденного поля
КонецЦикла;
Такой подход гарантирует, что ваша обработка не "упадет" после обновления конфигурации или при использовании в другой среде.
Важно помнить, что стандартная функция БСП часто ограничивается только коллекцией Реквизиты. Однако в регистрах накопления, сведений и бухгалтерии ключевая информация (такая как Организация или Склад) почти всегда хранится в Измерениях.
Разберем, как модифицировать алгоритм, чтобы он охватывал все возможные места хранения данных. Мы должны перебрать не только реквизиты, но и измерения, а также общие реквизиты, если они используются в системе.
Функция НайтиВсеПоляПоТипу(МетаданныеОбъекта, ИскомыйТип)
НайденныеПоля = Новый Массив;
// 1. Проверяем измерения (актуально для регистров)
Если ОбщегоНазначения.ЕстьСвойство(МетаданныеОбъекта, "Измерения") Тогда
Для Каждого Поле Из МетаданныеОбъекта.Измерения Цикл
Если Поле.Тип.СодержитТип(ИскомыйТип) Тогда
НайденныеПоля.Добавить(Поле.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
// 2. Проверяем стандартные реквизиты и обычные реквизиты
Для Каждого Поле Из МетаданныеОбъекта.Реквизиты Цикл
Если Поле.Тип.СодержитТип(ИскомыйТип) Тогда
НайденныеПоля.Добавить(Поле.Имя);
КонецЕсли;
КонецЦикла;
Возврат НайденныеПоля;
КонецФункции
При обработке больших массивов данных или анализе всей структуры метаданных (например, при поиске по всем регистрам базы), циклы по метаданным могут стать "узким местом". Рассмотрим основные советы по оптимизации:
Новый Массив внутри глубоко вложенных циклов может замедлять работу. Однако, как показывает практика современной платформы 8.3, конкатенация строк (Стр = Стр + Имя) работает еще медленнее на больших объемах из-за постоянного перераспределения памяти. Использование массива с финальным СтрСоединить() — наиболее сбалансированный вариант.Соответствие в оперативной памяти (или в кэшируемом модуле), где ключом будет имя таблицы, а значением — список найденных полей.Проанализируем ситуацию, когда в системе используются расширения. Если реквизит "Организация" был добавлен в документ через расширение, обычный перебор метаданных основной конфигурации может его не увидеть. При написании кода следует учитывать контекст выполнения. Если вы используете Метаданные.НайтиПоПолномуИмени(), платформа вернет актуальную структуру с учетом активных расширений.
Посмотрим на пример правильного получения метаданных для анализа:
// Вместо прямого обращения к Метаданные.Документы...
ОбъектМетаданных = СсылкаНаОбъект.Метаданные();
// Метод Метаданные() у ссылки всегда возвращает актуальное описание объекта
СписокПолей = ИменаРеквизитовПоТипу(ОбъектМетаданных, Тип("СправочникСсылка.Организации"));
Для решения задачи поиска по типу в 1С лучше всего использовать комбинацию стандартных методов БСП и собственных проверок. Помните:
Реквизиты, но и Измерения.СодержитТип() для корректной работы с составными типами данных.Использование готовых функций БСП — это не признак лени, а признак профессионального подхода, позволяющий избежать "изобретения велосипеда" и обеспечивающий более высокую стабильность кода при обновлениях системы.