Почему программный поиск номенклатуры по коду работает в файловой базе 1С, но не находит элементы в серверной?

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

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

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

Причина 1: Неявное форматирование чисел и влияние региональных настроек (локали)

Выясним, как формируется код номенклатуры при импорте. Очень часто исходные данные считываются из внешних текстовых файлов (CSV, TXT) или XML. Если код в файле представлен в виде числа (например, 12345), разработчики нередко преобразуют его следующим образом:

Код = Строка(Число(Спис[7]));

Рассмотрим, что происходит при выполнении этой строки кода в файловом и серверном режимах:

  1. В файловом варианте (на клиенте): База выполняется в контексте операционной системы пользователя. Если в региональных настройках ОС (панель управления Windows -> Региональные стандарты) для разделения групп разрядов чисел используется пробел, то функция Строка(12345) вернет строковое значение "12 345". Обратите внимание, что этот пробел является специальным неразрывным пробелом (символ с кодом 160). Если в справочнике «Номенклатура» коды заводились вручную или загружались аналогичным образом, то код элемента в базе данных также будет содержать этот неразрывный пробел ("12 345"). Поиск завершается успешно, так как строки полностью совпадают.
  2. В серверном варианте (на сервере 1С:Предприятие): Код выполняется в контексте службы ragent на сервере под учетной записью (например, usr1cv8). Серверные операционные системы (особенно на базе Linux или Windows Server с дефолтными английскими настройками локали) часто используют другие стандарты форматирования чисел. Функция Строка(12345) на сервере может вернуть строковое значение без пробелов ("12345") или с запятой в качестве разделителя ("12,345").

Когда сервер пытается выполнить поиск элемента методом НайтиПоКоду("12345"), СУБД сравнивает это значение с реальным кодом в базе данных, который записан как "12 345" (с неразрывным пробелом). Естественно, сервер сообщает, что элемент не найден.

Причина 2: Контекст исполнения кода в управляемых формах

Проанализируем требования платформы 1С к выполнению запросов и поиску в базах данных. Метод Справочники.Номенклатура.НайтиПоКоду() относится к объектной технике работы с базой данных. Согласно стандартам разработки 1С, подобные методы недоступны непосредственно на клиенте в управляемом приложении. Они должны выполняться строго в серверном контексте (процедуры с директивой &НаСервере или &НаСервереБезКонтекста).

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

Причина 3: Особенности обработки концевых пробелов (Trailing Spaces) в СУБД

Разберем еще один нюанс. Длина кода в справочнике «Номенклатура» в типовых конфигурациях обычно фиксированная (например, 11 символов). Если код элемента состоит из меньшего количества символов (например, 5 символов "12345"), то СУБД может хранить его, дополняя пробелами справа до полной длины: "12345 ".

Различные СУБД (MS SQL Server, PostgreSQL, файловая СУБД) по-разному обрабатывают концевые пробелы при сравнении строк. MS SQL Server при стандартных настройках сопоставления (Collation) может автоматически отсекать концевые пробелы при поиске, тогда как PostgreSQL или локальная файловая база данных будут требовать точного совпадения строки с учетом всех концевых пробелов.

---

Пошаговое руководство по решению проблемы

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

Шаг 1. Перенос логики поиска на сервер

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


&НаСервере
Функция НайтиНоменклатуруПоКодуНаСервере(Знач ИсходныйКод) Экспорт
    
    // Очищаем код от возможных случайных пробелов в начале и конце строки
    ОчищенныйКод = СокрЛП(ИсходныйКод);
    
    // Выполняем поиск по справочнику
    СсылкаНаТовар = Справочники.Номенклатура. НайтиПоКоду(ОчищенныйКод);
    
    Возврат СсылкаНаТовар;
    
КонецФункции

Шаг 2. Исключение неявного форматирования чисел

Категорически откажемся от конструкции Строка(Число()). Чтобы преобразовать считанное из файла число в строку без использования системных региональных настроек разделения триад, применим функцию Формат со специальным параметром группировки ЧГ=0 (Группировка = 0). Это гарантирует получение «чистой» строки на любом сервере:


// Неправильно:
// Код = Строка(Число(Спис[7]));

// Правильно:
ЧисловойКод = Число(Спис[7]);
Код = Формат(ЧисловойКод, "ЧГ=0");

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


ЧисловойКод = Число(Спис[7]);
Код = XMLСтрока(ЧисловойКод);

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

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


&НаСервере
Функция БезопасныйПоискПоКоду(Знач ПолученныйКод)
    
    // 1. Пробуем найти код в том виде, в котором он пришел
    НайденнаяСсылка = Справочники.Номенклатура.НайтиПоКоду(ПолученныйКод);
    
    // 2. Если не нашли, пробуем удалить все виды пробелов (обычные и неразрывные)
    Если НайденнаяСсылка.Пустая() Тогда
        // Удаляем неразрывные пробелы (код символа 160)
        КодБезПробелов = СтрЗаменить(ПолученныйКод, Символы.НПП, "");
        // Дополнительно удаляем обычные пробелы (код символа 32)
        КодБезПробелов = СтрЗаменить(КодБезПробелов, " ", "");
        
        НайденнаяСсылка = Справочники.Номенклатура.НайтиПоКоду(КодБезПробелов);
    КонецЕсли;
    
    Возврат НайденнаяСсылка;
    
КонецФункции

Шаг 4. Учет лидирующих нулей в коде

В некоторых конфигурациях коды номенклатуры имеют текстовый формат с лидирующими нулями (например, "00000012345" вместо "12345"). Метод НайтиПоКоду требует точного совпадения длины строки. Добавим дополнение кода нулями до нужной длины, определяя длину кода динамически из метаданных:


&НаСервере
Функция НайтиКодСЛидирующимиНулями(Знач ИсходныйКод)
    
    ДлинаКода = Метаданные.Справочники.Номенклатура.ДлинаКода;
    ОчищенныйКод = СокрЛП(ИсходныйКод);
    
    // Дополняем строку нулями слева до требуемой длины справочника
    ФорматированныйКод = Прав("00000000000000" + ОчищенныйКод, ДлинаКода);
    
    Возврат Справочники.Номенклатура.НайтиПоКоду(ФорматированныйКод);
    
КонецФункции

---

Настройка серверной отладки для контроля процесса

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

Выполним следующие шаги для включения отладки:

  1. Откроем реестр операционной системы на сервере, где запущен сервер 1С:Предприятие (команда regedit в Windows).
  2. Перейдем к ветке реестра службы сервера 1С. Обычно она находится по пути:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\1C:Enterprise 8.3 Server Agent... (имя ветки зависит от версии платформы).
  3. Найдем параметр ImagePath, который содержит строку запуска службы ragent.exe.
  4. Добавим в конец строки запуска параметр -debug. Пример измененного значения:
    "C:\Program Files\1cv8\8.3.21.1624\bin\ragent.exe" -srvc -agent -regport 1541 -port 1540 -range 1560:1591 -d "C:\Program Files\1cv8\srvinfo" -debug
  5. Перезапустим службу сервера 1С через консоль «Службы» (Services.msc).

После этого откроем Конфигуратор, перейдем в меню Отладка -> Подключение... и в списке доступных предметов отладки выберем серверные процессы вашей информационной базы. Теперь точки останова в серверных функциях будут успешно срабатывать.

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

← На главную