При разработке сервисных обработок, универсальных алгоритмов очистки данных, выгрузок или анализа конфигурации в 1С:Предприятие 8.3 часто возникает необходимость программно перебрать все существующие в базе справочники, а затем получить ссылки на каждый их элемент. Рассмотрим по шагам, как устроен этот механизм, какие методы платформы следует использовать и как обеспечить высокую производительность и безопасность при обработке данных.
Для того чтобы получить список всех справочников конфигурации, обратимся к глобальному объекту Метаданные. Коллекция Метаданные.Справочники содержит описания всех объектов метаданных данного типа. Разберем базовый цикл обхода:
Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
ИмяСправочника = МД_Справочник.Имя;
СинонимСправочника = МД_Справочник.Синоним;
// В переменной МД_Справочник доступно полное описание объекта метаданных
КонецЦикла;
Чтобы внутри цикла по метаданным обратиться к конкретным данным информационной базы, используем обращение к менеджеру справочника по его имени через коллекцию Справочники[ИмяСправочника]. Для получения элементов применим метод Выбрать():
Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
ИмяСправочника = МД_Справочник.Имя;
// Получаем выборку элементов текущего справочника
Выборка = Справочники[ИмяСправочника].Выбрать();
Пока Выборка.Следующий() Цикл
СсылкаНаЭлемент = Выборка.Ссылка;
// Выполняем необходимые действия со ссылкой
КонецЦикла;
КонецЦикла;
Проанализируем производительность предыдущего метода: использование Выбрать() последовательно считывает все поля объектов и может приводить к избыточному потреблению оперативной памяти на больших таблицах. Если перед нами стоит задача отобрать только определенные элементы (например, помеченные на удаление) или получить только ссылки, гораздо эффективнее формировать динамический запрос:
Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
ИмяСправочника = МД_Справочник.Имя;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Спр.Ссылка КАК Ссылка
|ИЗ
| Справочник." + ИмяСправочника + " КАК Спр";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
СсылкаНаЭлемент = Выборка.Ссылка;
// Обработка полученной ссылки
КонецЦикла;
КонецЦикла;
Если код выполняется в контексте пользователя с ограниченными правами, прямое обращение к справочнику может вызвать ошибку времени выполнения. Чтобы этого избежать, добавим проверку прав с помощью функции ПравоДоступа():
Для Каждого МД_Справочник Из Метаданные.Справочники Цикл
// Проверяем наличие прав на чтение объекта
Если Не ПравоДоступа("Чтение", МД_Справочник) Тогда
Продолжить;
КонецЕсли;
ИмяСправочника = МД_Справочник.Имя;
// Безопасный код выборки данных
КонецЦикла;
Если целью обхода является изменение или непосредственное удаление элементов, важно учитывать ограничения платформы и архитектурные правила:
Объект.Удалить() физически стирает запись из базы, игнорируя существующие связи в документах и регистрах, что приводит к появлению «битых» ссылок (<Объект не найден...>). Для проверки использования элемента перед удалением обязательно вызовем метод НайтиПоСсылкам().Предопределенный равно Истина, заблокировано платформой и вызовет исключение.НачатьТранзакцию() и ЗафиксироватьТранзакцию(), чтобы избежать перегрузки журнала транзакций СУБД и блокировки таблиц.&НаСервереБезКонтекста) или в фоновых заданиях.Посмотрим на пример безопасной проверки ссылок с помощью НайтиПоСсылкам():
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(СсылкаНаЭлемент);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Если ТаблицаСсылок.Количество() = 0 Тогда
// На элемент нет ссылок в других объектах базы данных
Иначе
// Элемент используется, удалять напрямую нельзя
КонецЕсли;