Ошибка метода НайтиСтроки() при переходе на платформу 8.3 и смене режима совместимости

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет Промышленность, строительство и АПК
← На главную

Переход со старых версий платформы 1С (например, с 8.2.19) на современные релизы ветки 8.3 часто сопровождается «мистическими» ошибками в коде, который годами работал безупречно. Одной из таких проблем является некорректное поведение метода НайтиСтроки() при поиске в табличных частях документов. Рассмотрим ситуацию, когда после обновления платформы до 8.3.21.1624 и изменения режима совместимости на 8.3.8, стандартный поиск по структуре перестает находить существующие записи или выдает непредсказуемые результаты.

Анализ проблемы: почему НайтиСтроки() перестает работать

Разберем типичный сценарий. В цикле происходит обход одной табличной части (например, Заявка), и для каждой строки выполняется поиск соответствий в другой табличной части (МатериальнаяСпецификация), которая принадлежит другому документу (Заказ). Код выглядит примерно так:


Для каждого Стр из Заявка Цикл
    Если ЗначениеЗаполнено(Стр.Номенклатура) Тогда
        // Поиск в ТЧ другого документа через ссылку
        МассиРезультатПоиска = Стр.НомерЗаказа.МатериальнаяСпецификация.НайтиСтроки(Новый Структура("Номенклатура", Стр.Номенклатура));
    КонецЕсли;
КонецЦикла;

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

Причина №1: Обращение к табличной части через точку от ссылки

Это самая распространенная архитектурная ошибка, которая проявляется именно при смене платформы. Когда мы пишем Стр.НомерЗаказа.МатериальнаяСпецификация, платформа выполняет следующие действия:

  1. Обращается к базе данных (или кэшу) для получения объекта НомерЗаказа.
  2. Считывает его табличную часть МатериальнаяСпецификация в память.
  3. Выполняет метод НайтиСтроки().

В новых версиях платформы обращение через точку внутри цикла может приводить к постоянному перечитыванию объекта. Если между итерациями цикла или из-за особенностей работы rphost кэш объекта обновляется некорректно, метод НайтиСтроки() может работать с «пустым» или неактуальным набором данных в памяти. Важный момент: индексы для быстрого поиска в коллекции строятся в момент обращения к ней. Если коллекция пересоздается динамически, индексы могут быть повреждены или не успеть инициализироваться.

Причина №2: Проблемы типизации и «пустые» значения

Часто в структуре поиска используются поля с разными типами данных (например, Строка и СправочникСсылка). Рассмотрим уточненный вариант кода, который учитывает возможную пустоту значений:


// Рассмотрим пример безопасного формирования структуры поиска
Если Стр.НоменклатураИнтермех <> "" Тогда
    Если ЗначениеЗаполнено(Стр.Номенклатура) Тогда
        // Поиск по двум полям: строке и ссылке
        ПараметрыОтбора = Новый Структура("НоменклатураИнтермех, Номенклатура", Стр.НоменклатураИнтермех, Стр.Номенклатура);
    Иначе
        // Поиск только по строке, если ссылка пустая
        ПараметрыОтбора = Новый Структура("НоменклатураИнтермех", Стр.НоменклатураИнтермех);
    КонецЕсли;
    МассиРезультатПоиска = Стр.НомерЗаказа.МатериальнаяСпецификация.НайтиСтроки(ПараметрыОтбора);
КонецЕсли;

Выясним причину, по которой это может не сработать. В платформе 8.3 поиск по строковым полям стал более чувствителен к невидимым символам (неразрывные пробелы, переносы строк). Если в НоменклатураИнтермех в одном месте записана строка с пробелом в конце, а в другом — без него, НайтиСтроки() не сочтет их идентичными. В режиме совместимости 8.2 такие различия иногда игнорировались или обрабатывались иначе на уровне СУБД.

Причина №3: Баги отладчика и платформы 8.3.21

Если при попытке посмотреть значение в табло отладчика вы видите странное поведение (например, обращение к индексу [912] внезапно превращается в [91]), это явный признак нестабильности текущего релиза платформы или повреждения кэша метаданных. В версии 8.3.21.1624 были зафиксированы ошибки, связанные с некорректным отображением индексов коллекций в отладке, что может сбивать разработчика с толку, создавая иллюзию отсутствия данных.

Решение №1: Выгрузка табличной части в Таблицу Значений

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

Рассмотрим правильный алгоритм:

  1. Перед началом цикла получим все необходимые данные одним запросом или выгрузкой.
  2. Загрузим их в типизированную таблицу значений.
  3. Выполним поиск по этой таблице.

// 1. Выгружаем спецификацию в ТЗ один раз до цикла
ТЗ_Спецификация = Стр.НомерЗаказа.МатериальнаяСпецификация.Выгрузить();

// 2. Теперь работаем с локальной копией данных в памяти
Для каждого Стр из Заявка Цикл
    ПараметрыОтбора = Новый Структура;
    ПараметрыОтбора.Вставить("Номенклатура", Стр.Номенклатура);
    
    // Поиск по ТЗ работает стабильнее и быстрее
    МассивРезультат = ТЗ_Спецификация.НайтиСтроки(ПараметрыОтбора);
    
    // Обработка результатов...
КонецЦикла;

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

Решение №2: Очистка строковых данных

Если поиск ведется по строковым полям (как НоменклатураИнтермех), крайне важно убедиться в отсутствии лишних пробелов. Посмотрим, как модифицировать код для повышения надежности:


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

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

Решение №3: Комплексное обслуживание базы данных

Если код корректен, а НайтиСтроки() всё равно ведет себя неадекватно после смены режима совместимости, выполните следующие действия:

Подводя итог, можно сказать, что проблема чаще всего кроется не в самом методе НайтиСтроки(), а в изменившемся механизме получения данных через точку от ссылки и особенностях работы кэша объектов в новых версиях 1С. Использование предварительной выгрузки данных в ТаблицаЗначений является «золотым стандартом» разработки, позволяющим избежать подобных проблем при любых обновлениях системы.

← На главную