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