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

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

Как перебрать элементы справочника в 1С

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

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

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

Ниже разобраны основные варианты перебора с примерами кода, особенности работы с иерархическими справочниками, отбором и типичные ошибки, которые приводят к лишним обращениям к базе данных.

Способ 1. Перебор через Выбрать() — базовый вариант

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

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

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

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

КонецЦикла;

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

Метод принимает параметры: Родитель (для иерархических справочников), Владелец (для подчинённых) и Отбор — структуру с условиями по реквизитам. Важно: отбор через параметр выполняется на стороне СУБД, а фильтрация уже внутри цикла — в памяти, что медленнее.

bsl
Отбор = Новый Структура("ПометкаУдаления", Ложь);
Выборка = Справочники.Контрагенты.Выбрать(,, Отбор);
Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Ссылка);
КонецЦикла;

Способ 2. Перебор через запрос — для сложных отборов

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

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

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

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

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

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

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

КонецЦикла;

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

Для иерархического обхода запрос позволяет использовать конструкцию ИТОГИ ПО и обход результата по группировкам — это единственный удобный способ получить дерево элементов одним обращением к базе.

Сравнение способов перебора

Выбрать() с циклом

Простые сценарии, обход по родителю или владельцу. Ограничение: слабые возможности отбора, нет соединений.

Запрос с Выбрать()

Сложные отборы, сортировка, соединения, большие объёмы. Требует знания языка запросов.

Запрос с Выгрузить()

Нужен многократный доступ к данным или поиск по таблице. Расходует память на всю таблицу целиком.

ПолучитьОбъект() в цикле

Только когда элемент нужно изменить и записать. Самый медленный вариант — не использовать для чтения.

Способ 3. Перебор с изменением элементов

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

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

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

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

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

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

КонецЦикла;

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

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

Иерархические справочники (например, «Номенклатура» с группами) требуют отдельного подхода. При вызове Выбрать() без параметров обходятся и группы, и элементы; различить их можно по свойству ЭтоГруппа.

Чтобы обойти элементы конкретной группы с учётом вложенности, в запросе используется условие Ссылка В ИЕРАРХИИ(&Группа). Это стандартный и быстрый способ выбрать всё поддерево.

Рекурсивный обход дерева

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

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

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

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

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

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

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

КонецЕсли;

КонецЦикла;

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

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

Отбор и фильтрация при переборе

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

Отбор в Выбрать() поддерживает только равенство по реквизитам, поэтому условия вида «содержит подстроку» или «больше значения» доступны только в запросе. Пометку удаления почти всегда стоит исключать явно, иначе в обработку попадут неактуальные элементы.

Маршрут решения

Как выбрать способ

Нужно просто прочитать все элементы или детей одного родителяИспользуйте Выбрать() с циклом Пока Следующий()
Нужен отбор по нескольким условиям, сортировка или соединение с другими даннымиИспользуйте запрос
Нужно изменить и сохранить элементыВыборка или запрос для получения ссылок, затем ПолучитьОбъект() и Записать()
Нужны все элементы группы с учётом вложенных подгруппЗапрос с условием Ссылка В ИЕРАРХИИ(&Группа)

Типичные ошибки и производительность

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

Вторая частая проблема — обращение к реквизитам через точку от ссылки внутри цикла в клиент-серверном варианте: каждое обращение может порождать отдельный запрос. Выбирайте все нужные поля сразу в запросе.

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

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

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

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

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

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

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

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

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

Счётчик меньше или больше ожидаемого — ошибка в отборе

Состав выборки
Норма

Нет помеченных на удаление и элементов чужих групп

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

В обработку попали лишние элементы

Время выполнения
Норма

Секунды или минуты на типовом объёме

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

Обработка работает часами или блокирует пользователей

Частые вопросы

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

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

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

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

Что быстрее: Выбрать() или запрос?

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

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

Напрямую перебор выполняется только на сервере. На клиенте вызывайте серверную процедуру (с директивой &НаСервере), которая выполнит обход и вернёт результат, например массив структур или таблицу значений.

Как прервать перебор досрочно?

Используйте оператор Прервать внутри цикла при выполнении условия — например, когда нужный элемент найден. Для пропуска текущей итерации без выхода из цикла применяется Продолжить.

Итог

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

Для чтения используйте Выбрать() или запрос, для изменения — ПолучитьОбъект() с записью, для иерархии — условие В ИЕРАРХИИ. Фильтруйте данные как можно раньше, исключайте помеченные на удаление и тестируйте массовые обработки на копии базы.