При работе с платформой 1С разработчики часто сталкиваются с необходимостью поиска элементов справочников по их коду. Казалось бы, простая задача, для которой существует встроенная функция НайтиПоКоду(). Однако, при использовании строковых кодов, особенно содержащих ведущие нули (например, "00001", "00123"), данная функция может вести себя неочевидно, что приводит к некорректным результатам поиска. Давайте разберем эту проблему подробнее и выясним, как ее эффективно решить.
НайтиПоКоду() может работать некорректно для строковых кодов с ведущими нулями?Мы выясним, что функция НайтиПоКоду() в 1С может иметь особенности при работе со строковыми кодами, которые выглядят как числа. Если код справочника в конфигурации имеет тип "Строка", но при этом содержит только цифры (например, "00001"), платформа может предпринять попытку неявного преобразования этого строкового значения в число перед сравнением. В результате такого преобразования строка "00001" превращается в число 1, "00123" — в число 123 и так далее. Если в справочнике элемент имеет код "00001" (строковый тип) и мы пытаемся найти его по строке "00001", но функция внутренне сравнивает 1 (число) с "00001" (строка), то совпадения не происходит.
Это поведение может быть связано с оптимизациями или историческими особенностями платформы, но важно понимать, что оно создает проблему, когда для нас принципиально важны ведущие нули как часть кода.
Наш первый шаг – всегда проверять тип данных как передаваемого параметра, так и самого реквизита "Код" в справочнике. Хотя реквизит "Код" в справочнике "Организации" обычно имеет строковый тип, передача строкового значения в НайтиПоКоду(), состоящего только из цифр, может спровоцировать упомянутое неявное преобразование.
Мы рассмотрим самый надежный и универсальный способ поиска элемента справочника по строковому коду, включая коды с ведущими нулями – это использование запросов 1С. Запросы позволяют явно указать условие сравнения и гарантировать, что сравнение будет производиться как со строками, без каких-либо неявных преобразований типов.
Разберем по шагам, как построить такой запрос:
Новый Запрос.Справочник.Организации). Ключевым моментом является условие ГДЕ Организации.Код = &Код. Здесь мы используем параметр &Код, что позволяет нам безопасно передавать значение для поиска.Запрос.УстановитьПараметр() для передачи искомого кода. Важно, что в качестве значения мы передаем именно строковый код, который мы хотим найти, например "00001". Система будет сравнивать его как строку со строковым полем "Код" в базе данных.РезультатЗапроса, из которого можем выбрать данные. Если в результате есть хотя бы одна строка (Результат.Следующий()), это означает, что элемент найден. Мы получаем его ссылку.Посмотрим на пример кода для поиска организации по строковому коду:
Функция НайтиОрганизациюПоКодуСтрокой(КодОрганизации)
// Проверяем, что входной параметр действительно строка и не пустой
Если ТипЗнч(КодОрганизации) <> Тип("Строка") Или ПустаяСтрока(КодОрганизации) Тогда
Сообщить("Код организации должен быть непустой строкой.", СтатусСообщения.Важное);
Возврат Неопределено;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Организации.Ссылка
|ИЗ
| Справочник.Организации КАК Организации
|ГДЕ
| Организации.Код = &Код"; // Явное строковое сравнение
Запрос.УстановитьПараметр("Код", КодОрганизации);
Попытка
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
Возврат Результат.Ссылка;
Иначе
Возврат Неопределено;
КонецЕсли;
Исключение
Сообщить("Ошибка при выполнении запроса: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
Возврат Неопределено;
КонецПопытки;
КонецФункции
// Пример использования:
// НайденнаяОрганизация = НайтиОрганизациюПоКодуСтрокой("00001");
// Если ЗначениеЗаполнено(НайденнаяОрганизация) Тогда
// Сообщить("Организация найдена: " + НайденнаяОрганизация.Наименование);
// Иначе
// Сообщить("Организация с кодом '00001' не найдена.");
// КонецЕсли;
Мы видим, что этот подход является наиболее гибким. Он позволяет нам не только искать по точному совпадению, но и добавлять другие условия (например, по наименованию, по группе) или использовать операторы сравнения строк, такие как ПОДОБНО или КАК, для более сложных сценариев поиска. Это особенно полезно, когда требуется высокая точность и предсказуемость результата.
НайтиПоРеквизиту()Другим эффективным способом поиска элемента справочника, который также обходит проблему неявного преобразования типов, является метод НайтиПоРеквизиту(). Этот метод предназначен для поиска элемента по значению произвольного реквизита справочника, включая его код.
Разберем, как использовать НайтиПоРеквизиту():
Справочники.Организации.НайтиПоРеквизиту(): Этот метод принимает два обязательных параметра: имя реквизита (в нашем случае "Код") и значение, по которому нужно искать.Неопределено, если элемент не найден.Посмотрим на пример кода для поиска организации с помощью НайтиПоРеквизиту():
Функция НайтиОрганизациюПоРеквизитуКод(КодОрганизации)
// Проверяем, что входной параметр действительно строка и не пустой
Если ТипЗнч(КодОрганизации) <> Тип("Строка") Или ПустаяСтрока(КодОрганизации) Тогда
Сообщить("Код организации должен быть непустой строкой.", СтатусСообщения.Важное);
Возврат Неопределено;
КонецЕсли;
Попытка
// Использование НайтиПоРеквизиту для точного строкового сравнения
НайденнаяОрганизация = Справочники.Организации.НайтиПоРеквизиту("Код", КодОрганизации);
Возврат НайденнаяОрганизация;
Исключение
Сообщить("Ошибка при поиске организации по реквизиту: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
Возврат Неопределено;
КонецПопытки;
КонецФункции
// Пример использования:
// НайденнаяОрганизация = НайтиОрганизациюПоРеквизитуКод("00001");
// Если ЗначениеЗаполнено(НайденнаяОрганизация) Тогда
// Сообщить("Организация найдена: " + НайденнаяОрганизация.Наименование);
// Иначе
// Сообщить("Организация с кодом '00001' не найдена.");
// КонецЕсли;
Мы заметим, что НайтиПоРеквизиту() является более простой в использовании альтернативой запросам для случаев, когда требуется поиск по одному реквизиту. Обычно этот метод показывает хорошую производительность для простых выборок, так как он оптимизирован платформой и не требует компиляции запроса каждый раз, как в случае с ручным построением объекта Запрос. Однако, если нам нужно искать по нескольким условиям или применять более сложные логические конструкции, запрос по-прежнему остается предпочтительным выбором.
Чтобы избежать подобных проблем в будущем и обеспечить надежность вашего кода, мы рекомендуем придерживаться следующих практик:
НайтиПоКоду() (хотя мы уже выяснили, что для нее это может не всегда помочь), убедитесь, что значение имеет тип Строка. Например, если код приходит из внешнего источника как число, преобразуйте его: Формат(ЧислоКода, "ЧН=; ЧВ0=0; ЧДЦ=0; ЧД=; ЧРГ=; ЧФ=; ЧС=; ЧП='0';"), где ЧП='0' дополняет ведущими нулями до нужной длины.Запрос и НайтиПоРеквизиту() являются предпочтительными методами, когда точность строкового сравнения критична.ВЫБРАТЬ Код ИЗ Справочник.Организации). Если по какой-то причине код "00001" был записан как "1", то ни один метод не найдет его по "00001".НайтиПоКоду() для строковых кодов, состоящих только из цифр: Несмотря на ее существование, мы пришли к выводу, что для строковых кодов, которые могут быть интерпретированы как числа (т.е. содержат только цифры), функция НайтиПоКоду() является менее надежной из-за потенциальных проблем с неявным преобразованием типов. Используйте ее только в тех случаях, когда вы абсолютно уверены, что код не будет восприниматься как число, или когда коды действительно являются числами.Мы подробно рассмотрели проблему некорректного поиска элементов справочника по строковому коду с ведущими нулями в 1С с использованием функции НайтиПоКоду(). Мы выяснили, что причина кроется в возможном неявном преобразовании строкового значения в числовое, что приводит к неверным результатам.
Для решения этой проблемы мы предложили два надежных и эффективных метода:
НайтиПоРеквизиту(): Этот метод проще в использовании для поиска по одному реквизиту и обеспечивает корректное строковое сравнение. Он может быть немного производительнее для простых случаев.Мы рекомендуем использовать один из этих двух методов для поиска по строковым кодам с ведущими нулями. Это позволит вам создавать более надежный, предсказуемый и легко поддерживаемый код в ваших 1С-решениях. Всегда помните о необходимости проверки типов данных и консистентности хранения кодов, чтобы минимизировать потенциальные ошибки.