Почему не ищется группа по наименованию при импорте из Excel в 1С и как правильно назначить родителя

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке обработок загрузки данных из внешних источников, таких как файлы Microsoft Excel, разработчики часто сталкиваются с ситуацией, когда метод НайтиПоНаименованию возвращает пустую ссылку, хотя визуально данные в файле и в базе 1С полностью совпадают. В результате не удается заполнить реквизит Родитель и правильно выстроить иерархию справочника.

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

Анализ проблемы: неявное форматирование чисел и неразрывные пробелы

Посмотрим на типовой фрагмент кода, в котором возникает ошибка:


// Из ячейки Excel с числовым кодом (например, 77987) считывается значение
ЗначениеЯчейки = Лист.Cells(i + 1, 3).Value;
ГруппаСсылка = Справочники.ИмпортДоговоровЗайма.НайтиПоНаименованию(Строка(ЗначениеЯчейки));
Элемент.Родитель = ГруппаСсылка;

Выясним причину, по которой поиск не находит созданную ранее группу. Свойство Value COM-объекта Excel для ячеек с числами возвращает значение числового типа. При вызове стандартной функции Строка(Число) платформа 1С применяет системный формат вывода чисел по умолчанию. В соответствии с региональными настройками русской локали все числа от 1000 и выше разделяются по триадам с использованием специального символа — неразрывного пробела (Символы.НПП, код 160).

В результате выражение Строка(77987) превращается в строку "77 987". Если наименование группы при создании было записано как "77987" или прочитано другим способом, то поиск по строке "77 987" завершится неудачей, так как строки не совпадают посимвольно.

Способ 1. Использование функции XMLСтрока

Наиболее быстрый и надежный способ преобразовать число в строку канонического вида без добавления разделителей групп разрядов — использовать системную функцию XMLСтрока.


ИмяГруппы = XMLСтрока(Лист.Cells(i + 1, 3).Value);
ГруппаСсылка = Справочники.ИмпортДоговоровЗайма.НайтиПоНаименованию(ИмяГруппы, Истина);
Если ЗначениеЗаполнено(ГруппаСсылка) Тогда
    Элемент.Родитель = ГруппаСсылка;
КонецЕсли;

Функция XMLСтрока преобразует любые примитивные типы (числа, даты, булево) в строковое представление по стандартам XML, где числа всегда формируются сплошной последовательностью цифр без неразрывных пробелов.

Способ 2. Использование функции Формат с отключением группировки разрядов

Рассмотрим стандартный способ явного форматирования чисел в платформе 1С с помощью функции Формат. Параметр ЧГ=0 отключает группировку разрядов.


ЧисловоеЗначение = Лист.Cells(i + 1, 3).Value;
ИмяГруппы = Формат(ЧисловоеЗначение, "ЧГ=0");
ГруппаСсылка = Справочники.ИмпортДоговоровЗайма.НайтиПоНаименованию(ИмяГруппы, Истина);

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

Способ 3. Очистка строки от неразрывных пробелов

Если в наименованиях из файла Excel могут встречаться как числа, так и текст с невидимыми служебными символами, проанализируем подход с очисткой строки функциями СтрЗаменить и СокрЛП:


СтрокаПоиска = СокрЛП(Строка(Лист.Cells(i + 1, 3).Value));
СтрокаПоиска = СтрЗаменить(СтрокаПоиска, Символы.НПП, ""); // Удаление неразрывных пробелов
СтрокаПоиска = СтрЗаменить(СтрокаПоиска, " ", "");          // Удаление обычных пробелов (при необходимости)

ГруппаСсылка = Справочники.ИмпортДоговоровЗайма.НайтиПоНаименованию(СтрокаПоиска, Истина);

Способ 4. Чтение свойства Text вместо Value через COM-объект

При работе с COM-объектом Excel свойство Value возвращает типизированное значение (число, дата), а свойство Text — строковое представление ячейки точно в таком виде, как оно отображается на экране в таблице.


// Свойство Text сразу возвращает строковый тип
ИмяГруппы = СокрЛП(Лист.Cells(i + 1, 3).Text);
ГруппаСсылка = Справочники.ИмпортДоговоровЗайма.НайтиПоНаименованию(ИмяГруппы, Истина);

Тонкости использования метода НайтиПоНаименованию

Разберем важные особенности метода НайтиПоНаименованию, которые необходимо учитывать при иерархическом поиске:

  1. Параметр точного соответствия: по умолчанию второй параметр метода равен Ложь, что означает поиск по началу строки. При поиске группы «10» метод может вернуть группу «100». Всегда передавайте Истина вторым параметром: НайтиПоНаименованию(Имя, Истина).
  2. Тип возвращаемого значения: метод возвращает готовую ссылку (СправочникСсылка). Конструкция ГруппаЭлемент.Ссылка является избыточной.
  3. Группы и элементы: метод не различает группы и элементы и возвращает первое найденное совпадение. Если в справочнике могут дублироваться наименования между группами и элементами, необходимо дополнительно проверять свойство ГруппаСсылка.ЭтоГруппа.

Оптимизация и повышение производительности импорта

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

  1. Кеширование групп через коллекцию Соответствие: постоянный вызов метода НайтиПоНаименованию в цикле отправляет отдельный SQL-запрос к базе данных на каждую строку файла. Гораздо эффективнее сохранить созданные ссылки на группы в память:
    
    КешГрупп = Новый Соответствие;
    
    // В первом цикле при создании групп:
    ГруппаОбъект = Справочники.ИмпортДоговоровЗайма.СоздатьГруппу();
    ГруппаОбъект.Наименование = ИмяГруппы;
    ГруппаОбъект.Записать();
    КешГрупп.Вставить(ИмяГруппы, ГруппаОбъект.Ссылка);
    
    // Во втором цикле при создании элементов:
    РодительСсылка = КешГрупп[ИмяРодителя];
    Если РодительСсылка <> Неопределено Тогда
        Элемент.Родитель = РодительСсылка;
    КонецЕсли;
    
  2. Использование транзакций: запись элементов пачками по 500–1000 штук внутри блока НачатьТранзакцию() ... ЗафиксироватьТранзакцию() ускоряет импорт в десятки раз.
  3. Корректное освобождение COM-объекта Excel: после завершения работы с Excel недостаточно вызвать Quit(). Переменным COM-соединения необходимо присвоить Неопределено, чтобы процесс EXCEL.EXE не оставался в диспетчере задач:
    
    Книга.Close(Ложь);
    Эксель.Quit();
    Книга = Неопределено;
    Лист = Неопределено;
    Эксель = Неопределено;
    
← На главную