Как обойти элементы справочника без групп в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Способ 1. Стандартный обход выборки с проверкой на группу

Самый распространенный и простой вариант — использование штатного метода ВыбратьЭлементы() с последующей фильтрацией в цикле. Выясним причину частой ошибки начинающих программистов в 1С 7.7: в этой платформе отсутствует тип Булево, поэтому логические методы возвращают числа 1 (Истина) или 0 (Ложь). Условие Если Спр.ЭтоГруппа() Тогда в 7.7 является синтаксически некорректным или может вести себя нестабильно — проверку необходимо выполнять строго на равенство единице.

Посмотрим на классический пример реализации:


Спр = СоздатьОбъект("Справочник.Номенклатура");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
    Если Спр.ЭтоГруппа() = 1 Тогда
        Продолжить;
    КонецЕсли;
    
    // Обработка конкретного элемента
    Сообщить("Найден элемент: " + Спр.Наименование);
КонецЦикла;

Обратите внимание на вызов метода: проверку Спр.ЭтоГруппа() = 1 можно выполнять напрямую от объекта выборки, обращение к Спр.ТекущийЭлемент().ЭтоГруппа() является избыточным.

Оптимизация обхода: «плоская» выборка

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

Для ускорения чтения данных передадим в метод параметр 0:


Спр = СоздатьОбъект("Справочник.Номенклатура");
// 0 — "плоский" обход справочника по текущему порядку сортировки
Спр.ВыбратьЭлементы(0);
Пока Спр.ПолучитьЭлемент() = 1 Цикл
    Если Спр.ЭтоГруппа() = 1 Тогда
        Продолжить;
    КонецЕсли;
    
    // Полезные действия с элементом
КонецЦикла;

Важно: даже при передаче параметра 0 группы из выборки не исчезают автоматически, поэтому проверка Спр.ЭтоГруппа() = 1 по-прежнему строго обязательна.

Способ 2. Использование встроенного языка запросов (черный запрос)

Вторым надежным способом является использование встроенного объекта Запрос. В языке запросов 1С 7.7 предусмотрена специальная синтаксическая конструкция без групп в секции группировки. Она позволяет на уровне платформы отсечь все папки еще до этапа обхода результатов.

Разберем пример запроса по справочнику:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(Сформировать)
|ТекЭлемент = Справочник.Номенклатура.ТекущийЭлемент;
|Группировка ТекЭлемент без групп;
|"//}}ЗАПРОС
;

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
    Возврат;
КонецЕсли;

Пока Запрос.Группировка("ТекЭлемент") = 1 Цикл
    // Запрос.ТекЭлемент содержит ссылку на элемент
    Сообщить("Элемент: " + Запрос.ТекЭлемент.Наименование);
КонецЦикла;

В среде разработчиков существует заблуждение, будто запрос в 1С 7.7 не может работать без агрегатных функций (например, Сумма или Счётчик). Это правило обязательно для регистров, однако при выборке данных из справочников запрос без функций возвращает корректную таблицу значений.

Важные нюансы при обработке справочников в 1С 7.7

Проанализируем практические ситуации, с которыми часто сталкиваются программисты при массовом обходе данных:

  1. Опасность модификации элементов в цикле выборки. Если внутри цикла вызвать метод Спр.Записать() на том же объекте, по которому открыта выборка через Спр.ВыбратьЭлементы(), внутренний курсор 1С 7.7 собьется. Это гарантированно приведет к пропуску части записей либо к зацикливанию обхода. Чтобы безопасно изменить данные, создайте второй вспомогательный объект (СпрМодификация = СоздатьОбъект("Справочник.Номенклатура")), позиционируйте его через СпрМодификация.НайтиЭлемент(Спр.ТекущийЭлемент()) и записывайте изменения через него. Второй надежный вариант — предварительно выгрузить ссылки во временный СписокЗначений, а затем обойти полученный список.
  2. Транзакции при массовой записи. Если в цикле выполняется изменение реквизитов и запись элементов, обязательно обрамляйте операции транзакциями (НачатьТранзакцию() и ЗафиксироватьТранзакцию()) пачками по 1000–5000 записей. Без этого производительность файловых (DBF) и SQL-баз катастрофически падает.
  3. Работа с подчиненными справочниками. Если справочник зависит от другого объекта, перед началом выборки необходимо установить фильтр по владельцу: Спр.ИспользоватьВладельца(ЭлементВладелец). Если же требуется обойти элементы вообще всех владельцев, владельца принудительно сбрасывают передачей пустой строки: Спр.ИспользоватьВладельца("").
  4. Периодические реквизиты. Если у справочника есть периодические реквизиты, перед вызовом ВыбратьЭлементы() обязательно зафиксируйте рабочую дату методом Спр.ИспользоватьДату(НужнаяДата), иначе платформа будет возвращать значения на текущую дату системы.
  5. Прямые запросы к базе данных (SQL / DBF). При работе через прямые SQL-запросы фильтрация по признаку группы осуществляется по физическому полю таблицы справочника — ISFOLDER. Значение 1 обозначает группу, а значение 2 — элемент. Таким образом, в блоке WHERE отбор элементов без групп строится с условием WHERE ISFOLDER = 2.
← На главную