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

Справочники и Данные · 8 мин

Как обойти справочник в 1С: перебор элементов в коде и запросе

Способы обойти справочник в 1С: выборка через Выбрать(), запрос, перебор с отбором и иерархией. Примеры кода, ошибки и проверка результата.

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

Неправильно выбранный способ обхода приводит к типичным проблемам: медленная обработка больших справочников, ошибки «Поле объекта не обнаружено», потеря иерархии или загрузка в память лишних данных. Ниже разобраны рабочие варианты с примерами кода и критериями выбора.

Способы обхода справочника: что выбрать

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

Сравнение вариантов

Выбрать()

Простой перебор всех элементов или с отбором по реквизиту. Ограничение: слабые возможности сортировки и отбора.

Запрос

Гибкий отбор, сортировка, итоги, соединения. Ограничение: результат — выборка, для изменения нужен отдельный ПолучитьОбъект().

Обход иерархии

Рекурсивный перебор групп и элементов дерева. Ограничение: сложнее код, легко получить зацикливание при ошибке.

Пакетная выборка

Обработка больших справочников частями. Ограничение: требует аккуратной организации цикла.

Обход через Выбрать(): базовый вариант

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

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

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

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

Продолжить;

КонецЕсли;

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

КонецЦикла;

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

Отбор = Новый Структура("ПометкаУдаления", Ложь);

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

Важно понимать: выборка содержит только поля, доступные через точку, и не является объектом. Попытка записать изменения напрямую в Выборка.Наименование ни к чему не приведёт — для изменения нужен объект.

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

Запрос — предпочтительный способ, когда нужен отбор по нескольким условиям, сортировка или обработка большого объёма. Запрос выполняется на сервере и возвращает только нужные поля, что снижает нагрузку.

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

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

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

|УПОРЯДОЧИТЬ ПО

| Наименование";

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

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

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

КонецЦикла;

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

Изменение элементов при обходе

Частая задача — не просто прочитать, а изменить реквизиты у всех найденных элементов. Для этого по ссылке из выборки получают объект, меняют поля и записывают.

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

Объект = Выборка.Ссылка.ПолучитьОбъект();

Объект.Комментарий = "Обработан пакетно";

Объект.Записать();

КонецЦикла;

Для массовых изменений оборачивайте запись в транзакцию либо фиксируйте её порциями, чтобы при сбое не потерять прогресс и не держать длинную блокировку. Перед массовой обработкой сделайте резервную копию базы или сначала выполните «сухой прогон» — обход без записи с выводом списка элементов, которые будут изменены.

Обход иерархического справочника

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

Процедура ОбойтиВетку(Родитель, Уровень)

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

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

Сообщить(СтрШаблон("%1%2", СтрПовторить(" ", Уровень * 2), Выборка.Наименование));

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

ОбойтиВетку(Выборка.Ссылка, Уровень + 1);

КонецЕсли;

КонецЦикла;

КонецПроцедуры

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

Порядок действий для массовой обработки
  1. 1
    Определите критерии отбора и проверьте их в консоли запросов
  2. 2
    Сделайте резервную копию базы или работайте на копии
  3. 3
    Напишите обход с выводом списка найденных элементов без записи
  4. 4
    Проверьте список глазами: не попали ли лишние элементы
  5. 5
    Добавьте запись с транзакцией и обработкой ошибок
  6. 6
    Выполните обработку и проверьте результат на нескольких элементах

Типичные ошибки при обходе справочника

Большинство проблем при переборе справочников связано с непониманием разницы между выборкой, ссылкой и объектом, а также с особенностями иерархии.

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

Отдельно отметим производительность: конструкция «в цикле получить объект и прочитать реквизит» для десятков тысяч элементов может выполняться минутами. Если нужно только прочитать данные — используйте запрос, он вернёт все поля одним обращением к базе.

Проверка результата обхода

После выполнения обработки убедитесь, что обойдено и изменено ожидаемое количество элементов. Самый простой способ — счётчик в цикле и сравнение с количеством по запросу.

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

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

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

Совпадает с количеством по контрольному запросу с тем же отбором

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

Разница — часть элементов пропущена или отобрана дважды

Значения изменённых реквизитов
Норма

У выборочных элементов реквизиты соответствуют задуманным

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

Реквизиты пустые или изменены у лишних элементов

Группы и иерархия
Норма

Структура дерева не изменилась, родители на месте

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

Элементы переехали в другие группы или потеряли родителя

FAQ

Как обойти только элементы без групп?

Добавьте в цикле проверку Если Выборка.ЭтоГруппа Тогда Продолжить, либо в запросе условие ГДЕ НЕ Ссылка.ЭтоГруппа. В методе Выбрать() группы исключаются только проверкой в цикле.

Чем отличается выборка от объекта справочника?

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

Как обойти подчинённый справочник по владельцу?

Передайте владельца вторым параметром: Справочники.ЕдиницыИзмерения.Выбрать(, ВладелецСсылка). В запросе используйте условие ГДЕ Владелец = &Владелец.

Почему обход справочника работает медленно?

Чаще всего из-за вызова ПолучитьОбъект() или обращений к базе внутри цикла. Перенесите чтение в запрос, а запись делайте порциями с транзакциями. Также проверьте, что отбор отсекает лишние элементы до цикла, а не внутри него.

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

Нет, менеджеры справочников и запросы доступны только на сервере. Организуйте серверную процедуру с директивой &НаСервере, а на клиент возвращайте готовый результат — например, массив структур или таблицу значений.

Итог

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

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