При разработке и сопровождении конфигураций на платформе 1С:Предприятие 7.7 часто возникает задача обработать только конечные элементы иерархического справочника, полностью исключив папки (группы). В отличие от платформы 1С 8.x, где есть отдельный тип данных Булево и гибкий язык запросов, в версии 7.7 разработчики нередко сталкиваются с платформенными особенностями и ограничениями. Разберем по шагам наиболее эффективные способы решения этой задачи, а также типичные подводные камни.
Самый распространенный и простой вариант — использование штатного метода ВыбратьЭлементы() с последующей фильтрацией в цикле. Выясним причину частой ошибки начинающих программистов в 1С 7.7: в этой платформе отсутствует тип Булево, поэтому логические методы возвращают числа 1 (Истина) или 0 (Ложь). Условие Если Спр.ЭтоГруппа() Тогда в 7.7 является синтаксически некорректным или может вести себя нестабильно — проверку необходимо выполнять строго на равенство единице.
Посмотрим на классический пример реализации:
Спр = СоздатьОбъект("Справочник.Номенклатура");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если Спр.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
// Обработка конкретного элемента
Сообщить("Найден элемент: " + Спр.Наименование);
КонецЦикла;
Обратите внимание на вызов метода: проверку Спр.ЭтоГруппа() = 1 можно выполнять напрямую от объекта выборки, обращение к Спр.ТекущийЭлемент().ЭтоГруппа() является избыточным.
Рассмотрим важный параметр метода ВыбратьЭлементы(). По умолчанию он вызывается со значением 1 — ВыбратьЭлементы(1), что означает иерархический обход справочника (дерево обходится сверху вниз с погружением во все вложенные ветки). Если структура каталога содержит большое количество уровней вложенности, такой обход может выполняться медленно.
Для ускорения чтения данных передадим в метод параметр 0:
Спр = СоздатьОбъект("Справочник.Номенклатура");
// 0 — "плоский" обход справочника по текущему порядку сортировки
Спр.ВыбратьЭлементы(0);
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если Спр.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
// Полезные действия с элементом
КонецЦикла;
Важно: даже при передаче параметра 0 группы из выборки не исчезают автоматически, поэтому проверка Спр.ЭтоГруппа() = 1 по-прежнему строго обязательна.
Вторым надежным способом является использование встроенного объекта Запрос. В языке запросов 1С 7.7 предусмотрена специальная синтаксическая конструкция без групп в секции группировки. Она позволяет на уровне платформы отсечь все папки еще до этапа обхода результатов.
Разберем пример запроса по справочнику:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|ТекЭлемент = Справочник.Номенклатура.ТекущийЭлемент;
|Группировка ТекЭлемент без групп;
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Возврат;
КонецЕсли;
Пока Запрос.Группировка("ТекЭлемент") = 1 Цикл
// Запрос.ТекЭлемент содержит ссылку на элемент
Сообщить("Элемент: " + Запрос.ТекЭлемент.Наименование);
КонецЦикла;
В среде разработчиков существует заблуждение, будто запрос в 1С 7.7 не может работать без агрегатных функций (например, Сумма или Счётчик). Это правило обязательно для регистров, однако при выборке данных из справочников запрос без функций возвращает корректную таблицу значений.
Проанализируем практические ситуации, с которыми часто сталкиваются программисты при массовом обходе данных:
Спр.Записать() на том же объекте, по которому открыта выборка через Спр.ВыбратьЭлементы(), внутренний курсор 1С 7.7 собьется. Это гарантированно приведет к пропуску части записей либо к зацикливанию обхода. Чтобы безопасно изменить данные, создайте второй вспомогательный объект (СпрМодификация = СоздатьОбъект("Справочник.Номенклатура")), позиционируйте его через СпрМодификация.НайтиЭлемент(Спр.ТекущийЭлемент()) и записывайте изменения через него. Второй надежный вариант — предварительно выгрузить ссылки во временный СписокЗначений, а затем обойти полученный список.НачатьТранзакцию() и ЗафиксироватьТранзакцию()) пачками по 1000–5000 записей. Без этого производительность файловых (DBF) и SQL-баз катастрофически падает.Спр.ИспользоватьВладельца(ЭлементВладелец). Если же требуется обойти элементы вообще всех владельцев, владельца принудительно сбрасывают передачей пустой строки: Спр.ИспользоватьВладельца("").ВыбратьЭлементы() обязательно зафиксируйте рабочую дату методом Спр.ИспользоватьДату(НужнаяДата), иначе платформа будет возвращать значения на текущую дату системы.ISFOLDER. Значение 1 обозначает группу, а значение 2 — элемент. Таким образом, в блоке WHERE отбор элементов без групп строится с условием WHERE ISFOLDER = 2.