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

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

Каждый разработчик 1С рано или поздно сталкивается с ситуацией, когда стандартный метод поиска по наименованию неожиданно возвращает пустую ссылку, хотя нужный элемент гарантированно присутствует в базе данных. Особенно часто это происходит при автоматическом импорте данных из внешних систем (файлов Excel, XML, JSON или через API), когда в качестве идентификатора используется текстовое наименование объекта.

В этой статье мы подробно разберем, почему возникает эта проблема, изучим внутренние механизмы платформы «1С:Предприятие», СУБД и предложим несколько надежных программных и архитектурных решений, которые позволят навсегда забыть об этой ошибке.

Выясняем техническую причину проблемы

Давайте проанализируем, что происходит на уровне платформы и базы данных, когда мы создаем элемент справочника с длинным названием. Возьмем классический пример строки из реальной практики:

"Средства для защиты кожи при негативном влиянии окружающей среды (например, воздействие пониженных температур, ветра) (от раздражения и повреждения кожи)"

Эта строка состоит из 19 слов и содержит ровно 153 символа (включая пробелы и знаки препинания).

Стандартный реквизит Наименование любого справочника в 1С имеет жесткое ограничение длины, заданное в конфигураторе в свойствах этого справочника. По умолчанию в платформе максимальная длина наименования может составлять до 150 символов (в зависимости от настроек конкретной конфигурации этот лимит часто уменьшают до 100, 80 или даже 50 символов).

Когда мы записываем новый элемент, платформа 1С и СУБД ведут себя следующим образом:

  1. При вызове метода Записать() платформа передает строку СУБД.
  2. База данных (MS SQL, PostgreSQL и др.) автоматически обрезает входящую строку до установленной в метаданных длины (в нашем случае — до 150 символов) без генерации ошибок или предупреждений.
  3. В базу записывается усеченная строка: "Средства для защиты кожи при негативном влиянии окружающей среды (например, воздействие пониженных температур, ветра) (от раздражения и повреждения кож" (ровно 150 символов, последние три буквы "и", "ж", "и" и закрывающая скобка были отброшены).

Когда в последующем коде мы пытаемся выполнить поиск элемента, используя полную строку из внешнего источника:


НайденнаяСсылка = Справочники.СмывающиеОбезвреживающиеСредства.НайтиПоНаименованию(ИскомаяСтрока, Истина);

Система пытается сопоставить исходные 153 символа с сохраненными в базе 150 символами. Так как мы указали второй параметр поиска как Истина (что означает строгое точное соответствие), СУБД выполняет операцию равенства строк. Очевидно, что строка длиной 153 символа не равна строке длиной 150 символов. Поиск возвращает пустую ссылку.

---

Решение 1: Динамическое усечение строки поиска (правильный подход)

Простейший способ решения проблемы — предварительно обрезать искомую строку перед вызовом поиска. Однако хардкодить числовые значения длины (например, писать функцию Лев(Строка, 150)) крайне не рекомендуется. Если в будущем длину наименования справочника изменят в конфигурации, ваш код снова начнет работать некорректно.

Давайте рассмотрим, как правильно получить ограничение длины динамически из метаданных конфигурации:


// Получаем максимально допустимую длину наименования для конкретного справочника
МаксДлина = Метаданные.Справочники.СмывающиеОбезвреживающиеСредства.ДлинаНаименования;

// Обрезаем исходную строку до размера, который физически может храниться в базе
СтрокаПоиска = СокрЛП(СтрокаТаблицыЗначений.СредствоЗащиты);
СтрокаПоиска = Лев(СтрокаПоиска, МаксДлина);

// Выполняем точный поиск по усеченной строке
НайденнаяСсылка = Справочники.СмывающиеОбезвреживающиеСредства.НайтиПоНаименованию(СтрокаПоиска, Истина);

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

---

Решение 2: Борьба с неразрывными пробелами и спецсимволами

При загрузке данных из внешних файлов (особенно из таблиц Microsoft Excel) разработчики часто сталкиваются с невидимой проблемой — наличием неразрывных пробелов (символ с кодом 160 или Символы.НПП в терминологии 1С).

Стандартная функция СокрЛП() отлично справляется с обычными пробелами (код 32), символами табуляции и перевода каретки, но она абсолютно «не видит» неразрывные пробелы. Если такой пробел окажется в конце строки или внутри нее, то даже правильно обрезанная строка не будет найдена базой данных.

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


// Функция нормализации поискового запроса
Функция ПодготовитьСтрокуДляПоиска(Знач ИсходнаяСтрока, МаксДлина) Экспорт
    
    // Заменяем неразрывные пробелы на стандартные
    Результат = СтрЗаменить(ИсходнаяСтрока, Символы.НПП, " ");
    
    // Убираем переводы строк и возвраты каретки
    Результат = СтрЗаменить(Результат, Символы.ПС, " ");
    Результат = СтрЗаменить(Результат, Символы.ВК, " ");
    
    // Удаляем двойные пробелы, которые могли образоваться после замен
    Пока Найти(Результат, "  ") > 0 Цикл
        Результат = СтрЗаменить(Результат, "  ", " ");
    КонецЦикла;
    
    // Удаляем пробелы по краям
    Результат = СокрЛП(Результат);
    
    // Обрезаем строку по максимальной длине из метаданных
    Возврат Лев(Результат, МаксДлина);
    
КонецФункции

Использование такой функции перед вызовом поиска гарантирует максимальную выверяемость данных и страхует от невидимых символов форматирования.

---

Решение 3: Поиск по частичному совпадению (ТочноеСоответствие = Ложь)

Вторым параметром метода НайтиПоНаименованию() является булево значение ТочноеСоответствие. Если передать туда значение Ложь, платформа выполнит поиск по левой (начальной) части наименования.

Давайте посмотрим на пример такого вызова:


// Ищем элемент без требования точного совпадения всей длины
НайденнаяСсылка = Справочники.СмывающиеОбезвреживающиеСредства. НайтиПоНаименованию(СтрокаТаблицыЗначений.СредствоЗащиты, Ложь);

При таком подходе СУБД найдет элемент, даже если поисковый запрос длиннее, чем значение в базе. Платформа просто сравнит первые 150 символов строки поиска с хранящимся в базе значением.

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

---

Решение 4: Поиск с использованием SQL-запроса и оператора ПОДОБНО

Иногда более гибким решением является написание классического запроса 1С. Запросы позволяют явно управлять логикой отбора и оптимизировать нагрузку на базу данных. Мы можем использовать оператор ПОДОБНО для поиска элемента по маске.

Давайте разберем пример построения такого запроса:


МаксДлина = Метаданные.Справочники.СмывающиеОбезвреживающиеСредства.ДлинаНаименования;
СтрокаДляПоиска = ПодготовитьСтрокуДляПоиска(СтрокаТаблицыЗначений.СредствоЗащиты, МаксДлина);

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 2
    |	СмывающиеСредства.Ссылка КАК Ссылка,
    |	СмывающиеСредства.Наименование КАК Наименование
    |ИЗ
    |	Справочник.СмывающиеОбезвреживающиеСредства КАК СмывающиеСредства
    |ГДЕ
    |	СмывающиеСредства.Наименование ПОДОБНО &ШаблонПоиска";

// Добавляем символ процента в конец для поиска по маске начала строки
Запрос.УстановитьПараметр("ШаблонПоиска", СтрокаДляПоиска + "%");

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    
    // Если найдено более одного элемента, можем зафиксировать неоднозначность
    Если Выборка.Количество() > 1 Тогда
        ЗаписьЖурналаРегистрации("ИмпортДанных", УровеньЖурналаРегистрации.Предупреждение, , , 
            "Найдено несколько соответствий для: " + СтрокаДляПоиска);
    КонецЕсли;
    
    НайденнаяСсылка = Выборка.Ссылка;
Иначе
    НайденнаяСсылка = Справочники.СмывающиеОбезвреживающиеСредства.ПустаяСсылка();
КонецЕсли;

---

Решение 5: Архитектурный подход (Реквизит «НаименованиеПолное»)

Если специфика вашего бизнеса требует хранения действительно длинных наименований (например, сложные названия химических веществ, лекарств, официальные длинные наименования контрагентов для печатных форм), хранить их в стандартном реквизите Наименование — архитектурная ошибка.

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

  1. Стандартный реквизит «Наименование» ограничивается разумным пределом (например, 100 или 150 символов). Он служит для быстрого визуального выбора в списках и отображения в интерфейсе пользователя.
  2. Создается дополнительный реквизит справочника с именем НаименованиеПолное (или ОфициальноеНаименование) с типом Строка неограниченной длины (или с большим ограничением, например, 1000 символов).
  3. При создании элемента полное имя записывается в реквизит НаименованиеПолное, а его сокращенная и обрезанная копия автоматически помещается в стандартное Наименование.
  4. Поиск уникальных элементов при импорте осуществляется запросом именно по реквизиту НаименованиеПолное.

Давайте посмотрим, как выглядит эффективный поиск по полному наименованию неограниченной длины с помощью запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	СмывающиеСредства.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.СмывающиеОбезвреживающиеСредства КАК СмывающиеСредства
    |ГДЕ
    |	СмывающиеСредства.НаименованиеПолное = &НаименованиеПолное";

Запрос.УстановитьПараметр("НаименованиеПолное", СокрЛП(СтрокаТаблицыЗначений.СредствоЗащиты));

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

Этот способ полностью исключает любые проблемы с потерей окончаний слов или символов при поиске и сопоставлении данных.

---

Решение 6: Увеличение длины наименования через расширение конфигурации

Если вы работаете в типовой конфигурации, находящейся на поддержке (например, «1С:Бухгалтерия» или «1С:ERP»), и не хотите снимать её с замка ради изменения одного свойства, вы можете использовать механизм расширения конфигурации.

Для этого выполните следующие действия:

  1. Создайте новое расширение конфигурации (или откройте существующее).
  2. Найдите необходимый справочник в дереве объектов основной конфигурации.
  3. Нажмите правой кнопкой мыши на справочник и выберите команду «Добавить в расширение».
  4. В расширении перейдите в свойства справочника и измените значение свойства Длина наименования до необходимого вам размера (например, до максимально возможных 150 символов).
  5. Сохраните и примените расширение.

Это позволит расширить возможности хранения данных без усложнения процесса последующих обновлений вашей базы данных.

← На главную