Как в цикле обойти все справочники и их элементы в 1С 8.3?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке сервисных обработок, универсальных алгоритмов очистки данных, выгрузок или анализа конфигурации в 1С:Предприятие 8.3 часто возникает необходимость программно перебрать все существующие в базе справочники, а затем получить ссылки на каждый их элемент. Рассмотрим по шагам, как устроен этот механизм, какие методы платформы следует использовать и как обеспечить высокую производительность и безопасность при обработке данных.

Шаг 1. Перебор метаданных справочников

Для того чтобы получить список всех справочников конфигурации, обратимся к глобальному объекту Метаданные. Коллекция Метаданные.Справочники содержит описания всех объектов метаданных данного типа. Разберем базовый цикл обхода:


Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
    ИмяСправочника = МД_Справочник.Имя;
    СинонимСправочника = МД_Справочник.Синоним;
    
    // В переменной МД_Справочник доступно полное описание объекта метаданных
КонецЦикла;

Шаг 2. Обход элементов каждого справочника через объектную выборку

Чтобы внутри цикла по метаданным обратиться к конкретным данным информационной базы, используем обращение к менеджеру справочника по его имени через коллекцию Справочники[ИмяСправочника]. Для получения элементов применим метод Выбрать():


Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
    ИмяСправочника = МД_Справочник.Имя;
    
    // Получаем выборку элементов текущего справочника
    Выборка = Справочники[ИмяСправочника].Выбрать();
    Пока Выборка.Следующий() Цикл
        СсылкаНаЭлемент = Выборка.Ссылка;
        // Выполняем необходимые действия со ссылкой
    КонецЦикла;
КонецЦикла;

Шаг 3. Оптимизация обхода с помощью динамических запросов

Проанализируем производительность предыдущего метода: использование Выбрать() последовательно считывает все поля объектов и может приводить к избыточному потреблению оперативной памяти на больших таблицах. Если перед нами стоит задача отобрать только определенные элементы (например, помеченные на удаление) или получить только ссылки, гораздо эффективнее формировать динамический запрос:


Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
    ИмяСправочника = МД_Справочник.Имя;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Спр.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник." + ИмяСправочника + " КАК Спр";
        
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        СсылкаНаЭлемент = Выборка.Ссылка;
        // Обработка полученной ссылки
    КонецЦикла;
КонецЦикла;

Шаг 4. Проверка прав доступа и исключение ошибок

Если код выполняется в контексте пользователя с ограниченными правами, прямое обращение к справочнику может вызвать ошибку времени выполнения. Чтобы этого избежать, добавим проверку прав с помощью функции ПравоДоступа():


Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
    // Проверяем наличие прав на чтение объекта
    Если Не ПравоДоступа("Чтение", МД_Справочник) Тогда
        Продолжить;
    КонецЕсли;
    
    ИмяСправочника = МД_Справочник.Имя;
    // Безопасный код выборки данных
КонецЦикла;

Правила безопасности при массовой модификации и удалении элементов

Если целью обхода является изменение или непосредственное удаление элементов, важно учитывать ограничения платформы и архитектурные правила:

  1. Контроль ссылочной целостности: Прямой вызов метода Объект.Удалить() физически стирает запись из базы, игнорируя существующие связи в документах и регистрах, что приводит к появлению «битых» ссылок (<Объект не найден...>). Для проверки использования элемента перед удалением обязательно вызовем метод НайтиПоСсылкам().
  2. Предопределенные элементы: Непосредственное удаление элементов, у которых свойство Предопределенный равно Истина, заблокировано платформой и вызовет исключение.
  3. Транзакции и порционная обработка: Массовые операции следует выполнять порциями (например, по 500–1000 элементов) с явным вызовом НачатьТранзакцию() и ЗафиксироватьТранзакцию(), чтобы избежать перегрузки журнала транзакций СУБД и блокировки таблиц.
  4. Выполнение на сервере: Все ресурсоемкие переборы метаданных и таблиц базы данных должны производиться исключительно в серверных процедурах без контекста формы (&НаСервереБезКонтекста) или в фоновых заданиях.

Посмотрим на пример безопасной проверки ссылок с помощью НайтиПоСсылкам():


МассивСсылок = Новый Массив;
МассивСсылок.Добавить(СсылкаНаЭлемент);

ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Если ТаблицаСсылок.Количество() = 0 Тогда
    // На элемент нет ссылок в других объектах базы данных
Иначе
    // Элемент используется, удалять напрямую нельзя
КонецЕсли;
← На главную