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

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

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

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

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

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

Материал ориентирован на встроенный язык 1С:Предприятие 8.3. Примеры работают как в толстом, так и в тонком клиенте, на сервере и в фоновых заданиях. Отдельно разобраны варианты для иерархических справочников, отборов и обхода помеченных на удаление элементов.

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

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

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

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

Запрос (ВЫБРАТЬ ... ИЗ Справочник)

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

Выбрать() + обход выборки

Удобен для последовательной обработки с изменением элементов. Медленнее запроса на больших объёмах.

Динамический список

Для отображения пользователю с отборами и сортировкой. Не предназначен для пакетной обработки в коде.

ПолучитьОбъект() по каждой ссылке

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

Получение всех элементов запросом

Запрос — основной и рекомендуемый способ. Минимальный вариант выглядит так:

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

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

"ВЫБРАТЬ

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

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

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

|ИЗ

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

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

Выборка = Результат.Выбрать();

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

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

КонецЦикла;

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

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

Перебор элементов через метод Выбрать()

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

Выборка = Справочники.Контрагенты.Выбрать();

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

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

Продолжить;

КонецЕсли;

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

КонецЦикла;

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

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

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

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

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

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

КонецЦикла;

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

Отбор элементов по условию

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

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

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

"ВЫБРАТЬ

| Контрагенты.Ссылка КАК Ссылка

|ИЗ

| Справочник.Контрагенты КАК Контрагенты

|ГДЕ

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

| И Контрагенты.Родитель = &Родитель";

Запрос.УстановитьПараметр("Родитель", НужнаяГруппа);

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

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

Отбор = Новый Структура;

Отбор.Вставить("Владелец", ОрганизацияСсылка);

Выборка = Справочники.ДоговорыКонтрагентов.Выбрать(, , Отбор);

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

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

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

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

| Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)

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

Запрос.УстановитьПараметр("Группа", ГруппаНоменклатуры);

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

Порядок действий для полной выгрузки справочника
  1. 1
    Определите цель: чтение данных, изменение элементов или вывод пользователю.
  2. 2
    Для чтения составьте запрос с нужными полями и условиями (пометка удаления, группы, иерархия).
  3. 3
    Выполните запрос и обойдите выборку или выгрузите результат в таблицу значений.
  4. 4
    Для изменения элементов получайте объект только внутри цикла и только для отобранных ссылок.
  5. 5
    Проверьте результат: количество обработанных элементов, отсутствие помеченных на удаление и групп там, где их быть не должно.

Производительность и ограничения на больших объёмах

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

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

Отдельное ограничение — права доступа. Запрос без ключевого слова РАЗРЕШЕННЫЕ вернёт ошибку, если у пользователя нет прав на часть данных. В регламентных операциях код обычно выполняется в привилегированном режиме, но в пользовательских обработках добавляйте РАЗРЕШЕННЫЕ, чтобы получать только доступные элементы.

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

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

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

Совпадает с числом элементов в списке справочника (с учётом отборов по пометке удаления и группам)

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

Меньше ожидаемого без явных отборов — проверьте права и условия запроса

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

Нет помеченных на удаление и групп, если они исключались

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

Присутствуют группы или удалённые элементы — условие ГДЕ не сработало

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

Запрос на чтение выполняется за секунды даже на крупном справочнике

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

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

Проверка результата и типичные ошибки

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

Частая ошибка новичков — обращение к реквизиту через точку от ссылки в цикле: Выборка.Ссылка.СтавкаНДС. Если реквизит не выбран в запросе, каждое такое обращение — отдельный запрос к базе. Правильно — добавить нужный реквизит в список полей запроса один раз.

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

Итог

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

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

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

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

Запросом с агрегатной функцией: «ВЫБРАТЬ КОЛИЧЕСТВО(Ссылка) КАК Количество ИЗ Справочник.Номенклатура». Это выполняется на уровне СУБД и не требует обхода элементов. Добавьте условие ГДЕ, если нужно исключить помеченные на удаление или группы.

Как получить только элементы, не помеченные на удаление?

Добавьте в запрос условие «ГДЕ НЕ Справочник.ПометкаУдаления». В методе Выбрать() отдельного параметра для этого нет — фильтруйте внутри цикла проверкой свойства ПометкаУдаления выборки или используйте запрос.

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

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

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

Отберите по владельцу: в запросе условие «ГДЕ Договоры.Владелец = &Контрагент», в Выбрать() — структура отбора с ключом Владелец. Поле Владелец стандартное и индексированное, поэтому такой отбор работает быстро.

Почему запрос возвращает меньше элементов, чем видно в списке?

Наиболее вероятные причины: у пользователя ограничены права на уровне записей (RLS) — тогда часть строк отсекается; в запросе стоит лишнее условие; либо в списке отображаются помеченные на удаление, а запрос их исключает. Проверьте запрос в консоли запросов под полными правами.

Можно ли получить все объекты справочника без запроса и Выбрать()?

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