Разработка и Конфигурация · 10 мин
Как получить все элементы справочника в 1С
Способы получить все элементы справочника 1С: Выбрать(), запрос, ВыбратьИерархически(). Примеры кода, обход групп, отбор, типичные ошибки и проверка результата.
Получение всех элементов справочника — одна из самых частых задач при разработке и доработке конфигураций 1С. Она возникает при заполнении табличных частей, синхронизации данных, построении отчётов и массовой обработке информации. В зависимости от задачи используются разные механизмы: метод Выбрать(), запрос к базе данных или иерархический обход.
Выбор способа влияет на производительность и корректность результата. Например, выборка через Выбрать() удобна для простого перебора, а запрос — когда нужны отборы, сортировка и соединения с другими таблицами. Ошибка в выборе механизма на больших справочниках приводит к заметному замедлению работы.
Ниже разобраны основные способы получения элементов справочника на встроенном языке 1С, особенности работы с иерархическими справочниками, отборы и типичные ошибки, которые допускают разработчики.
Способ 1. Получение элементов через метод Выбрать()
Самый простой способ перебрать все элементы справочника — метод Выбрать() менеджера справочника. Он возвращает объект типа «Выборка из справочника», который обходится в цикле методом Следующий(). Каждая итерация даёт ссылку на элемент, а реквизиты доступны через точку.
Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Элемент: " + Выборка.Наименование + ", ссылка: " + Выборка.Ссылка);
КонецЦикла;
Метод Выбрать() принимает три необязательных параметра: родитель (для иерархических справочников), владелец (для подчинённых) и отбор (структура с условиями по реквизитам). Если параметры не указаны, выбираются все элементы верхнего уровня — для неиерархического справочника это и есть все элементы.
Важная особенность: выборка читает данные порциями по мере обхода, поэтому она экономична по памяти. Однако обращение к реквизитам через точку внутри цикла может порождать дополнительные обращения к базе, если реквизит не входит в выборку. Для массовых обработок лучше получать объект методом ПолучитьОбъект() только там, где нужно изменение данных.
Способ 2. Получение элементов запросом
Запрос — предпочтительный способ, когда нужны отборы, сортировка, группировка или соединение с другими таблицами. Запрос выполняется на сервере СУБД одним обращением и, как правило, быстрее выборки при сложных условиях.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления
|УПОРЯДОЧИТЬ ПО
| Наименование";
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
Сообщить(Результат.Наименование);
КонецЦикла;
Обратите внимание на условие НЕ ПометкаУдаления. Запрос по умолчанию возвращает и помеченные на удаление элементы — это частая причина «лишних» строк в обработках. Метод Выбрать() также возвращает помеченные элементы, если отдельно не задать отбор.
Если нужны не отдельные поля, а сразу таблица значений, используйте Запрос.Выполнить().Выгрузить(). Результат удобно передавать в табличное поле формы или использовать для дальнейшей обработки без повторных обращений к базе.
Сравнение способов получения элементов
Простой перебор, чтение по мере обхода, экономия памяти. Слабые возможности отбора — только равенство по реквизитам.
Сложные отборы, сортировка, соединения, итоги. Требует написания текста запроса, но быстрее на больших объёмах.
Обход иерархии в порядке дерева групп. Подходит только для иерархических справочников.
Способ 3. Обход иерархического справочника
Для иерархических справочников (например, «Номенклатура» с группами товаров) обычный Выбрать() без параметров вернёт только элементы верхнего уровня. Чтобы получить все элементы с учётом вложенности, есть два подхода.
Первый — метод ВыбратьИерархически(). Он обходит справочник в порядке иерархии: сначала группа, затем её элементы и подгруппы. Внутри цикла признак группы проверяется свойством ЭтоГруппа.
Выборка = Справочники.Номенклатура.ВыбратьИерархически();
Пока Выборка.Следующий() Цикл
Если Выборка.ЭтоГруппа Тогда
Продолжить; // пропускаем группы, нужны только элементы
КонецЕсли;
Сообщить(Выборка.Наименование);
КонецЦикла;
Второй подход — запрос с условием ЭтоГруппа = ЛОЖЬ либо соединение с таблицей иерархии. Если нужны элементы конкретной группы с учётом всех вложенных подгрупп, в запросе используют оператор В ИЕРАРХИИ:
Запрос.Текст =
"ВЫБРАТЬ Ссылка, Наименование
|ИЗ Справочник.Номенклатура
|ГДЕ Ссылка В ИЕРАРХИИ(&Группа) И НЕ ЭтоГруппа";
Запрос.УстановитьПараметр("Группа", ГруппаОтбора);
Отбор и фильтрация элементов
Получать абсолютно все элементы нужно редко — чаще требуется подмножество по условиям. В методе Выбрать() отбор передаётся структурой, где ключ — имя реквизита, а значение — искомое значение. Поддерживается только сравнение на равенство:
Отбор = Новый Структура;
Отбор.Вставить("Владелец", КонтрагентСсылка);
Выборка = Справочники.ДоговорыКонтрагентов.Выбрать(, КонтрагентСсылка);
Для подчинённых справочников (например, «Договоры контрагентов») все элементы конкретного владельца получают передачей владельца вторым параметром Выбрать() или условием Владелец = &Владелец в запросе. Это стандартный способ получить, например, все договоры одного контрагента или все единицы измерения одной номенклатурной позиции.
Если условия сложнее равенства — диапазоны, «содержит», «не равно», несколько условий «ИЛИ» — используйте только запрос. Попытка выбрать всё через Выбрать() и фильтровать в цикле на большом справочнике приводит к чтению лишних данных и замедлению обработки.
- 1Определите, иерархический ли справочник и нужны ли группы в результате
- 2Если нужен простой перебор без условий — используйте Выбрать() или ВыбратьИерархически()
- 3Если нужны отборы, сортировка или соединения — напишите запрос
- 4Добавьте условие на ПометкаУдаления, если помеченные элементы не нужны
- 5Проверьте результат на тестовой базе: количество элементов и корректность отбора
Изменение элементов при обходе
Частая задача — не просто прочитать, а изменить все элементы справочника: заполнить новый реквизит, переназначить группу, обновить наименования. В этом случае для каждого элемента получают объект методом ПолучитьОбъект(), изменяют и записывают.
Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.ЭтоГруппа Тогда
Продолжить;
КонецЕсли;
Объект = Выборка.Ссылка.ПолучитьОбъект();
Объект.Комментарий = "Обработано";
Объект.Записать();
КонецЦикла;
Массовая запись — потенциально опасная операция. Перед запуском обработки на рабочей базе сделайте резервную копию и сначала проверьте логику на копии базы или на ограниченном отборе из нескольких элементов. Ошибка в коде цикла может испортить тысячи элементов, и откат потребует восстановления из копии.
При больших объёмах записывайте элементы порциями внутри транзакции разумного размера и выводите прогресс обработки, чтобы пользователь видел, что процесс не завис. Для типовых конфигураций проверьте, не переопределяют ли подписки на события записи дополнительную логику — она может замедлить массовую запись или изменить данные неожиданным образом.
Типичные ошибки и проверка результата
Разработчики при получении элементов справочника регулярно сталкиваются с одними и теми же проблемами. Знание их заранее экономит время отладки.
Отдельно стоит упомянуть права доступа. Если обработка выполняется под пользователем с ограниченными правами, выборка может вернуть не все элементы из-за RLS (ограничения доступа на уровне записей). Для административных обработок, где нужны гарантированно все данные, код выполняют в привилегированном модуле или используют УстановитьПривилегированныйРежим(Истина).
Как проверить результат
Совпадает с количеством в списке справочника с теми же отборами
Меньше ожидаемого — проверьте иерархию, отборы и права доступа
Исключены, если не нужны, либо осознанно включены
Помеченные элементы попадают в обработку и отчёты
Обработка справочника завершается за приемлемое время
Заметные паузы — вероятно, ПолучитьОбъект() или запрос в цикле
Частые вопросы
Чем отличается Выбрать() от ВыбратьИерархически()?
Метод Выбрать() без параметров возвращает элементы одного уровня (по умолчанию — верхнего). ВыбратьИерархически() обходит весь справочник в порядке дерева: группы и их содержимое с учётом вложенности. Для неиерархического справочника разницы нет.
Как получить только элементы без групп?
В цикле обхода проверяйте свойство ЭтоГруппа и пропускайте группы через Продолжить. В запросе добавьте условие «ГДЕ НЕ ЭтоГруппа» — это быстрее, так как фильтрация выполняется на уровне СУБД.
Почему выборка возвращает больше элементов, чем видно в списке справочника?
Чаще всего причина в помеченных на удаление элементах: они не отображаются в списке при стандартных настройках, но выбираются программно. Добавьте условие по ПометкаУдаления. Вторая возможная причина — отбор по владельцу или родителю в интерфейсе списка.
Что быстрее: Выбрать() или запрос?
Для простого полного перебора разница невелика. Запрос выигрывает при отборах, сортировке и соединениях, так как всё выполняется одним обращением к СУБД. Выборка удобнее, когда не нужно заранее загружать весь результат в память.
Как получить все элементы подчинённого справочника по владельцу?
Передайте ссылку владельца вторым параметром: Справочники.Договоры.Выбрать(, ВладелецСсылка). Либо используйте запрос с условием «Владелец = &Владелец». Без указания владельца будут выбраны элементы всех владельцев.
Можно ли получить элементы справочника без программирования?
Да. В режиме предприятия список справочника можно вывести на печать или сохранить в табличный документ через меню «Ещё». Также универсальные отчёты и обработка «групповое изменение реквизитов» в типовых конфигурациях позволяют просматривать и обрабатывать элементы без написания кода.
Что важно запомнить
Простой перебор — Выбрать() с циклом Пока Следующий(). Иерархия — ВыбратьИерархически() или условие В ИЕРАРХИИ в запросе. Отборы и сортировка — запрос. Всегда учитывайте ПометкаУдаления, признак ЭтоГруппа и права доступа, а массовую запись выполняйте только после резервного копирования.