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

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

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

Разбор исходной ситуации

Рассмотрим типичный фрагмент кода, который используется для чтения данных из Excel через ТабличныйДокумент и последующего поиска транспортного средства (ТС) в справочнике:


Для НомерСтроки = 6 По КоличесвтоСтрок Цикл
    // Читаем текст из второй колонки (наименование ТС)
    ТСИзТабДок = ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2).Текст;
    
    // Пытаемся найти ссылку в справочнике
    ТС = Справочники.ТС.НайтиПоНаименованию(ТСИзТабДок);
    
    Если ТС.Пустая() Тогда
        Сообщить("Элемент не найден: " + ТСИзТабДок);
    КонецЕсли;
КонецЦикла;

Проблема заключается в том, что даже если в переменной ТСИзТабДок находится строка, которая «на глаз» совпадает с названием в 1С, метод поиска может не сработать. Разберем по шагам причины этого поведения.

Причина 1: Ограничение длины наименования в метаданных

Выясним самую коварную причину, с которой столкнулся автор темы. В системе 1С каждый реквизит справочника, включая стандартное Наименование, имеет фиксированную длину (например, 25, 50 или 100 символов). Рассмотрим, что происходит при несовпадении длин:

  1. При записи элемента в справочник вручную или программно, если вводимая строка длиннее лимита, 1С автоматически обрезает ее до максимально допустимой длины.
  2. При получении данных из Excel строка может содержать полный текст (например, 30 символов), в то время как в базе сохранено только 25 символов.
  3. Метод НайтиПоНаименованию пытается найти точное соответствие полной строки из 30 символов. Так как в базе физически нет строки длиннее 25 символов, поиск завершается неудачей.

Решение: Проверим длину реквизита Наименование в конфигураторе. Если она меньше, чем данные в файле, необходимо либо увеличить длину в метаданных, либо обрезать искомую строку функцией Лев(СтрокаИзExcel, МаксДлина) перед поиском.

Причина 2: Невидимые символы и неразрывные пробелы

Проанализируем структуру текста, приходящего из Excel. Часто ячейки содержат не только буквы, но и спецсимволы, такие как неразрывный пробел (код 160). Обычная функция СокрЛП удаляет только стандартные пробелы (код 32). Если в конце строки из файла затесался неразрывный пробел, визуально в отладчике строки будут одинаковыми, но для системы это разные значения.

Для очистки данных воспользуемся следующим подходом:


// Удаляем стандартные пробелы и неразрывные пробелы
ЧистоеНаименование = СокрЛП(СтрЗаменить(ТСИзТабДок, Символы.НПП, ""));
ТС = Справочники.ТС.НайтиПоНаименованию(ЧистоеНаименование);

Причина 3: Разница между свойством Текст и Значение

При работе с объектом ТабличныйДокумент важно понимать разницу между свойствами области ячеек. Посмотрим на них внимательнее:

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


Обл = ТабДок.Область(НомерСтроки, 2, НомерСтроки, 2);
Если Обл.СодержитЗначение Тогда
    ТСИзТабДок = СокрЛП(Строка(Обл.Значение));
Иначе
    ТСИзТабДок = СокрЛП(Обл.Текст);
КонецЕсли;

Причина 4: Параметр ТочноеСоответствие

Метод НайтиПоНаименованию имеет второй параметр — ТочноеСоответствие. По умолчанию он равен Ложь. Это означает, что 1С ищет элемент, наименование которого начинается с искомой строки.

Важный нюанс: Если в базе есть элементы "Газель" и "Газель 123", то при поиске по строке "Газель" с параметром Ложь система вернет первый попавшийся элемент. Если же установить Истина, поиск будет строгим. Всегда используйте Истина, если вам нужно найти конкретный объект, а не похожий по началу названия.

Оптимизация: Использование запросов вместо поиска в цикле

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

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


// 1. Сначала подготовим кэш всех наименований ТС
КэшТС = Новый Соответствие;
Выборка = Справочники.ТС.Выбрать();
Пока Выборка.Следующий() Цикл
    // Ключ - наименование в верхнем регистре (для исключения проблем с регистром), значение - ссылка
    КэшТС.Вставить(ВРег(Выборка.Наименование), Выборка.Ссылка);
КонецЦикла;

// 2. В цикле загрузки просто берем данные из памяти
Для НомерСтроки = 6 По КоличесвтоСтрок Цикл
    НаименованиеИзФайла = СокрЛП(ТабДок.Область(НомерСтроки, 2).Текст);
    СсылкаНаТС = КэшТС.Получить(ВРег(НаименованиеИзФайла));
    
    Если СсылкаНаТС = Неопределено Тогда
        // Обработка ситуации, когда в справочнике нет такого ТС
    КонецЕсли;
КонецЦикла;

Этот метод работает в десятки раз быстрее, так как обращение к базе данных происходит всего один раз в самом начале.

Резюме и рекомендации

Для успешного поиска элементов при импорте из внешних систем всегда следуйте этим правилам:

  1. Проверяйте длину метаданных: убедитесь, что поле в 1С может вместить всю строку из файла.
  2. Очищайте входные данные: используйте СокрЛП и удаляйте неразрывные пробелы через СтрЗаменить.
  3. Приводите к регистру: используйте ВРег для искомой строки и данных в базе, чтобы избежать проблем с разным написанием (например, "тс" и "ТС").
  4. Используйте отладчик: проверяйте фактическую длину строки (функция СтрДлина) для обоих сравниваемых значений — это сразу покажет наличие скрытых символов.

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

← На главную