К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как перебрать все справочники 1С: практическое руководство

Как перебрать все справочники 1С: обход через метаданные, выборка элементов, запросы к справочникам. Примеры кода на встроенном языке, типичные ошибки и FAQ.

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

Ниже разобраны рабочие способы на встроенном языке 1С: коллекция Метаданные.Справочники, менеджеры Справочники.ИмяСправочника, метод Выбрать() и запросы. Примеры применимы к платформе 8.3 в управляемом и обычном приложении; отличия клиент-серверного контекста оговорены отдельно.

Обход всех видов справочников через метаданные

Коллекция Метаданные.Справочники содержит описания всех справочников, существующих в конфигурации. Обход этой коллекции нужен, когда требуется получить список видов справочников, их имена, синонимы, длину кода и наименования, наличие иерархии и владельцев — без обращения к данным.

Для Каждого СправочникМетаданные Из Метаданные.Справочники Цикл

Сообщить("Справочник: " + СправочникМетаданные.Имя

+ " | Синоним: " + СправочникМетаданные.Синоним

+ " | Иерархический: " + СправочникМетаданные.Иерархический);

КонецЦикла;

Такой цикл выполняется быстро, поскольку читает только структуру конфигурации, а не таблицы базы данных. Его удобно использовать в универсальных обработках: например, чтобы заполнить список выбора «какой справочник очистить» или «где искать дубли».

Обратите внимание: обращение к данным конкретного справочника по имени из метаданных выполняется через индексированное свойство менеджера — Справочники[СправочникМетаданные.Имя]. Это ключевой приём для универсального кода, который не знает заранее состав конфигурации.

Перебор элементов одного справочника методом Выбрать()

Метод Выбрать() возвращает выборку элементов справочника, которую можно обойти в цикле Пока Выборка.Следующий() Цикл. Метод принимает необязательные параметры: отбор, порядок, родителя и владельца.

Выборка = Справочники.Номенклатура.Выбрать();

Пока Выборка.Следующий() Цикл

Если Выборка.ЭтоГруппа Тогда

Продолжить;

КонецЕсли;

Сообщить(Выборка.Код + " — " + Выборка.Наименование);

КонецЦикла;

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

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

Перебор элементов запросом: когда это быстрее

Запрос к таблице справочника — предпочтительный способ, когда нужен отбор по произвольным реквизитам, сортировка, группировка или соединение с другими таблицами. Запрос выполняется на сервере СУБД и обычно заметно быстрее перебора выборки с проверками в коде.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Ссылка,

| Номенклатура.Наименование КАК Наименование

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления

| И НЕ Номенклатура.ЭтоГруппа";

Результат = Запрос.Выполнить().Выбрать();

Пока Результат.Следующий() Цикл

Сообщить(Результат.Наименование);

КонецЦикла;

Если нужно только подсчитать количество элементов или проверить наличие хотя бы одного, не перебирайте всё — используйте агрегатные функции КОЛИЧЕСТВО или конструкцию ВЫБРАТЬ ПЕРВЫЕ 1. Это снимает лишнюю нагрузку, особенно на больших справочниках вроде номенклатуры или контрагентов.

Универсальный обход элементов всех справочников

Задача «перебрать все элементы всех справочников» решается вложенной конструкцией: внешний цикл по Метаданные.Справочники, внутри — запрос с динамически формируемым текстом, поскольку имя таблицы нельзя передать параметром запроса.

Для Каждого СпрМета Из Метаданные.Справочники Цикл

Запрос = Новый Запрос;

Запрос.Текст = СтрШаблон(

"ВЫБРАТЬ Т.Ссылка ИЗ Справочник.%1 КАК Т

|ГДЕ НЕ Т.ПометкаУдаления", СпрМета.Имя);

Выборка = Запрос.Выполнить().Выбрать();

Количество = 0;

Пока Выборка.Следующий() Цикл

Количество = Количество + 1;

КонецЦикла;

Сообщить(СпрМета.Имя + ": " + Количество + " элементов");

КонецЦикла;

Такой код ляжет в основу обработок аудита: поиска пустых ссылок, подсчёта неиспользуемых элементов, сверки количества записей между базами. Учтите, что на больших базах полный обход всех справочников может занять заметное время — запускайте его в фоновом задании и не в часы пиковой нагрузки.

Порядок действий для универсальной обработки
  1. 1
    Создайте внешнюю обработку с серверной процедурой
  2. 2
    В цикле по Метаданные.Справочники сформируйте текст запроса через СтрШаблон с именем таблицы
  3. 3
    Выполните запрос и обойдите выборку, собирая нужные данные в структуру или таблицу значений
  4. 4
    Оберните обход в попытку-исключение, чтобы ошибка на одном справочнике не прерывала весь обход
  5. 5
    Выведите результат пользователю и проверьте его на тестовой копии базы

Особенности: иерархия, владельцы, предопределённые элементы

При обходе иерархических справочников решите заранее, нужны ли группы. В запросе группы отсекаются условием НЕ Т.ЭтоГруппа. Если требуется обход дерева сверху вниз (например, для выгрузки структуры папок), используйте рекурсивные запросы по родителю или итоги ИТОГИ ПО ... ИЕРАРХИЯ.

Подчинённые справочники (с владельцами) корректнее перебирать в связке с владельцем: либо параметром Владелец метода Выбрать(), либо соединением в запросе. Перебор подчинённого справочника «в лоб» без учёта владельца часто бессмысленен — элементы разных владельцев могут иметь одинаковые наименования.

Предопределённые элементы имеют признак Предопределенный. Их нельзя удалить интерактивно, а программное удаление или переименование ломает код конфигурации, который обращается к ним по имени. При обработках очистки и удаления дублей предопределённые элементы обязательно исключайте условием НЕ Т.Предопределенный.

Типичные ошибки
01
Изменение элементов внутри цикла обхода выборки — пропуск или повторная обработка элементов из-за сбоя сортировки
02
Попытка передать имя таблицы параметром запроса — параметры работают только для значений, имя подставляется в текст через СтрШаблон
03
Забытый фильтр ЭтоГруппа — группы попадают в обработку и искажают результат
04
Получение объекта через ПолучитьОбъект() для каждого элемента без необходимости — резкое падение производительности на больших справочниках
05
Обход всех справочников без обработки исключений — один проблемный справочник прерывает всю операцию

Производительность и безопасность на больших базах

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

Длительные операции запускайте через ДлительныеОперации.ВыполнитьВФоне() (в конфигурациях на БСП) или через фоновые задания, чтобы не блокировать сеанс пользователя и получить возможность отслеживать прогресс. Перед любой обработкой, изменяющей данные (удаление дублей, замена ссылок, массовое изменение реквизитов), сделайте выгрузку базы и прогоните сценарий на копии.

Для проверки результата массовой обработки полезно сравнить контрольные числа: количество элементов до и после, количество помеченных на удаление, результат типовой проверки ссылочной целостности (Тестирование и исправление в режиме проверки ссылок).

Контрольные точки

Как проверить результат обхода

Количество обработанных элементов
Норма

Совпадает с количеством по запросу КОЛИЧЕСТВО с теми же отборами

Тревожный признак

Меньше ожидаемого — часть элементов пропущена, проверьте фильтры и изменения внутри цикла

Ошибки в журнале регистрации
Норма

Нет ошибок за период выполнения обработки

Тревожный признак

Есть ошибки блокировок или обращений — снизьте размер порции, добавьте обработку исключений

Ссылки на изменённые элементы
Норма

Проверка ссылочной целостности не выявляет битых ссылок

Тревожный признак

Появились объекты с неразрешёнными ссылками — откатите изменения из копии

FAQ

Как перебрать справочники, к которым у пользователя нет прав?

Цикл по метаданным выполнится, но запрос к таблице без прав вызовет ошибку нарушения прав доступа. Решение — выполнять код в привилегированном модуле (УстановитьПривилегированныйРежим(Истина)) либо проверять доступность через ПравоДоступа("Чтение", СпрМета) и пропускать недоступные справочники.

Чем отличается Выбрать() от ВыбратьИерархически()?

ВыбратьИерархически() возвращает элементы с обходом по уровням иерархии: сначала группа, затем её содержимое. Обычный Выбрать() возвращает плоский список в порядке сортировки. Для выгрузки деревьев удобнее иерархическая выборка, для пакетной обработки — обычная или запрос.

Как найти, в каких справочниках есть ссылка на конкретный элемент?

Используйте метод НайтиПоСсылкам(): передайте массив с искомой ссылкой, и он вернёт таблицу всех объектов метаданных, где ссылка встречается. Это стандартный способ проверки перед удалением элемента.

Можно ли перебрать справочники на клиенте в управляемом приложении?

Нет, работа с данными справочников (выборки, запросы, объекты) доступна только на сервере. На клиенте можно перебирать лишь уже полученные коллекции (таблицы значений, массивы). Код обхода размещайте в серверной процедуре общего модуля или модуля формы с признаком «НаСервере».

Как перебрать только помеченные на удаление элементы всех справочников?

В цикле по Метаданные.Справочники выполняйте запрос с условием ГДЕ Т.ПометкаУдаления и собирайте ссылки в общий массив. Полученный массив можно передать в штатную процедуру удаления помеченных объектов или обработать вручную с контролем ссылочной целостности.

Итог

Что важно запомнить

Виды справочников перебираются через Метаданные.Справочники, элементы — через Выбрать() или запрос; для универсального обхода имя таблицы подставляется в текст запроса через СтрШаблон. Не изменяйте элементы внутри цикла выборки, фильтруйте группы и предопределённые элементы, а массовые обработки запускайте порциями в фоне после проверки на копии базы.