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

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

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

Многие разработчики пробуют решить эту задачу с помощью штатного объекта Запрос, однако сталкиваются с неожиданным поведением: запрос по группам возвращает пустой результат. Выясним причину этой особенности и разберем корректные способы решения задачи как штатными средствами встроенного языка, так и через прямые SQL-запросы.

Почему штатный объект «Запрос» в 1С 7.7 не находит папки?

Проанализируем архитектуру встроенного языка запросов платформы 1С 7.7. Штатный объект Запрос предназначен исключительно для выборки детальных записей — конечных элементов справочника. Группировки в тексте запроса строятся поверх существующих элементов.

Из этого следуют два важных ограничения:

  1. Если папка пустая и не содержит внутри себя ни одного элемента, штатный Запрос вообще не включит такую группу в результат выборки.
  2. Условие в тексте запроса (например, по реквизиту Наименование) накладывается на элементы, а не на сами группы. При попытке отфильтровать выборку по имени группы условие отсечет все строки, и результат окажется пустым.

Для гарантированного обхода папок следует использовать либо последовательную выборку методами самого справочника, либо прямой SQL-запрос к таблице базы данных.

Способ 1. Штатная выборка средствами встроенного языка 1С 7.7

Рассмотрим по шагам реализацию задачи без использования внешних библиотек и компонентов. Этот способ универсален и одинаково надежно работает как в файловом режиме (DBF), так и в клиент-серверном (SQL).

  1. Позиционирование на корневой группе. Используем метод НайтиПоНаименованию с третьим параметром 2, который указывает платформе искать исключительно среди групп.
  2. Ограничение выборки родителем. Устанавливаем фильтр по родителю методом ИспользоватьРодителя(). Метод ВключатьПодчиненные(1) позволит просматривать все вложенные уровни иерархии (если передать 0, выборка пойдет только по прямому первому уровню вложенности).
  3. Разделение объектов выборки и создания. Критически важно: нельзя вызывать метод Новый() на том же экземпляре объекта справочника, по которому выполняется цикл ПолучитьЭлемент(). Вызов Новый() сбросит указатель текущей выборки. Для добавления нового элемента всегда используем отдельный независимый экземпляр справочника.

Посмотрим на пример программного кода:


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

Способ 2. Использование прямого SQL-запроса через 1С++ (для баз SQL)

Если информационная база работает под управлением Microsoft SQL Server, а справочник содержит десятки тысяч элементов, штатный перебор может занять продолжительное время. В такой ситуации разберем более быстрое решение — использование внешней компоненты 1С++ и класса ODBCRecordSet.

В структуре таблиц 1С 7.7 признак группы хранится в поле ISFOLDER (значение 2 соответствует группе/папке, а 1 — конечному элементу). Поле наименования обозначается как DESCR.

Рассмотрим пример процедуры с выполнением прямого запроса:


Процедура СформироватьSQL()
    Перем Запрос, ТекстЗапроса, ТЗ, СпрСоздание, ИмяИскомойПапки, ИмяНовогоЭлемента;
    
    ИмяИскомойПапки = "Онлайн версия";
    ИмяНовогоЭлемента = "Новый релиз";
    
    Попытка
        Запрос = СоздатьОбъект("ODBCRecordSet");
    Исключение
        Если ЗагрузитьВнешнююКомпоненту("1cpp.dll") = 0 Тогда
            Предупреждение("Компонента 1cpp.dll не найдена в каталоге базы или в BIN!");
            Возврат;
        КонецЕсли;
        Запрос = СоздатьОбъект("ODBCRecordSet");
    КонецПопытки;
    
    // Формируем прямой запрос к таблице справочника
    ТекстЗапроса = "
    |SELECT id [Элем $Справочник.Программы]
    |FROM $Справочник.Программы
    |WHERE isfolder = 2 
    |  AND descr LIKE '%:Парам%'
    |";
    
    Запрос.УстановитьТекстовыйПараметр("Парам", ИмяИскомойПапки);
    ТЗ = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
    
    // Обходим полученную таблицу значений и создаем элементы в найденных группах
    СпрСоздание = СоздатьОбъект("Справочник.Программы");
    ТЗ.ВыбратьСтроки();
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        СпрСоздание.ИспользоватьРодителя(ТЗ.Элем);
        СпрСоздание.Новый();
        СпрСоздание.Наименование = ИмяНовогоЭлемента;
        СпрСоздание.Записать();
    КонецЦикла;
    
    Предупреждение("Элементы успешно созданы!");
КонецПроцедуры

Обратите внимание: если необходимо строго ограничить поиск только веткой родительской папки «Дистрибутив», в блок WHERE прямого SQL-запроса можно добавить условие по идентификатору родителя parentid = :ИД_Родителя или использовать конструкцию В ИЕРАРХИИ(:Родитель).

Итоги

При работе с иерархией справочников в 1С 7.7 важно помнить:

  1. Штатный объект Запрос не подходит для выборки пустых групп и фильтрации по наименованиям папок.
  2. Для решения задачи средствами встроенного языка используем связку НайтиПоНаименованию() с флагом поиска по группам, методы ИспользоватьРодителя(), ВключатьПодчиненные() и проверку ЭтоГруппа() = 1.
  3. Создание новых записей в цикле обхода выборки обязательно должно выполняться через отдельный объект справочника.
← На главную