Одной из самых распространенных и в то же время загадочных проблем при разработке в 1С является ситуация, когда программный поиск объекта по реквизиту возвращает пустую ссылку, хотя визуально данные в базе присутствуют. Особенно часто это происходит при работе со строковыми идентификаторами, такими как штрихкоды. Разберем детально причины этой проблемы на примере конфигурации 1С:Управление торговлей 10.3 и методов платформы 1С:Предприятие 8.
Прежде чем приступать к отладке кода, проанализируем, где именно хранятся данные. В типовой конфигурации УТ 10.3 штрихкоды по умолчанию не являются реквизитами справочника Номенклатура. Они хранятся в независимом регистре сведений Штрихкоды. Если в вашей базе поиск идет через Справочники.Номенклатура.НайтиПоРеквизиту("Штрихкод", ...), это означает одно из двух:
Номенклатура вручную добавлен новый реквизит Штрихкод.Важно: Если реквизит добавлен вручную, убедитесь, что у него установлено свойство Индексировать. Без индекса метод НайтиПоРеквизиту может работать некорректно или крайне медленно на больших объемах данных.
Выясним причину, связанную с типами данных. В 1С строковые реквизиты могут иметь фиксированную или переменную длину. Если для реквизита Штрихкод установлена фиксированная длина (например, 13 символов), система всегда будет дополнять значение пробелами справа до указанного лимита.
Рассмотрим пример. В базе хранится штрихкод "65672891851 " (с двумя пробелами в конце). Если вы ищете строку "65672891851", поиск не даст результата, так как для метода НайтиПоРеквизиту требуется полное совпадение строки.
Посмотрим на пример кода, который часто приводит к ошибке:
НайденнаяНоменклатура = Справочники.Номенклатура.НайтиПоРеквизиту("Штрихкод", СокрЛП(СтрТчНом.Штрихкод));
Если Не НайденнаяНоменклатура.Пустая() Тогда
СтрТчНом.Номенклатура1с = НайденнаяНоменклатура;
КонецЕсли;
Использование функции СокрЛП удаляет пробелы из искомого значения, но если в базе данных значение хранится с пробелами (из-за фиксированной длины), сопоставление не произойдет. В этом случае следует либо отказаться от фиксированной длины в конфигураторе, либо дополнять искомую строку пробелами до нужной длины.
Часто при импорте данных из внешних файлов (Excel, CSV) в строку попадают невидимые символы. Самый "коварный" из них — неразрывный пробел (код символа 160). Стандартная функция СокрЛП удаляет только обычные пробелы (код 32). Если в конце штрихкода стоит неразрывный пробел, визуально в карточке товара он не виден, но поиск по обычной строке его не найдет.
Проанализируем ситуацию в отладчике. Чтобы точно понять, что хранится в базе, используйте следующий прием: сравните эталонный объект (который вы видите глазами) с тем, что вы пытаетесь найти.
// Возьмите ссылку на номенклатуру, которая точно имеет этот штрихкод
ОбъектИзБазы = Справочники.Номенклатура.НайтиПоКоду("00001");
ШтрихкодВБазе = ОбъектИзБазы.Штрихкод;
ИскомыйШтрихкод = СокрЛП(СтрТчНом.Штрихкод);
// Сравните длину строк
Длина1 = СтрДлина(ШтрихкодВБазе);
Длина2 = СтрДлина(ИскомыйШтрихкод);
// Проверьте коды каждого символа, если длины не совпадают
Для Номер = 1 По СтрДлина(ШтрихкодВБазе) Цикл
Сообщить("Символ №" + Номер + ": Код " + КодСимвола(ШтрихкодВБазе, Номер));
КонецЦикла;
Обратите внимание на проверку результата в исходном сообщении автора темы: Если НайденнаяНоменклатура <> Неопределено. Это классическая ошибка начинающего разработчика. Методы поиска в 1С (такие как НайтиПоРеквизиту, НайтиПоКоду, НайтиПоНаименованию) никогда не возвращают Неопределено. Они возвращают Пустую ссылку соответствующего типа.
Правильная проверка должна выглядеть так:
НайденнаяНоменклатура = Справочники.Номенклатура.НайтиПоРеквизиту("Штрихкод", НужныйШтрихкод);
Если Не НайденнаяНоменклатура.Пустая() Тогда
// Объект найден
КонецЕсли;
Разберем, почему использование запросов предпочтительнее метода НайтиПоРеквизиту. Запрос позволяет гибко работать со строками и не зависеть от индексации одного конкретного поля (хотя индексация все равно важна для производительности). Кроме того, если штрихкоды хранятся в регистре сведений (как это сделано в типовой УТ 10.3), запрос становится единственным верным решением.
Посмотрим на пример запроса для поиска номенклатуры по штрихкоду из регистра сведений:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Штрихкоды.Владелец КАК Номенклатура
|ИЗ
| РегистрСведений.Штрихкоды КАК Штрихкоды
|ГДЕ
| Штрихкоды.Штрихкод = &Штрихкод";
Запрос.УстановитьПараметр("Штрихкод", СокрЛП(ИскомоеЗначение));
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
НоменклатураСсылка = Выборка.Номенклатура;
КонецЕсли;
Выясним еще одну деталь: штрихкоды формата EAN-13 состоят из 13 цифр. Однако штрихкоды типа UPC-A содержат 12 цифр. При записи в базу 1С часто автоматически дополняет 12-значный код ведущим нулем, превращая его в EAN-13. Если вы ищете "65672891851" (11 или 12 знаков), а в базе хранится "065672891851", прямое сравнение через НайтиПоРеквизиту выдаст ложь.
Рекомендации для стабильной работы поиска:
СокрЛП как для записываемого значения, так и для искомого.Штрихкоды, а не к реквизитам справочника.Проанализировав все вышеперечисленные шаги, мы можем сделать вывод: наиболее частой причиной неудачи является несоответствие типов или наличие скрытых пробелов в строках фиксированной длины. Тщательная проверка через отладчик и использование запросов помогут избежать подобных проблем в будущем.