Переход со старых версий платформы 1С (например, с 8.2.19) на современные релизы ветки 8.3 часто сопровождается «мистическими» ошибками в коде, который годами работал безупречно. Одной из таких проблем является некорректное поведение метода НайтиСтроки() при поиске в табличных частях документов. Рассмотрим ситуацию, когда после обновления платформы до 8.3.21.1624 и изменения режима совместимости на 8.3.8, стандартный поиск по структуре перестает находить существующие записи или выдает непредсказуемые результаты.
Разберем типичный сценарий. В цикле происходит обход одной табличной части (например, Заявка), и для каждой строки выполняется поиск соответствий в другой табличной части (МатериальнаяСпецификация), которая принадлежит другому документу (Заказ). Код выглядит примерно так:
Для каждого Стр из Заявка Цикл
Если ЗначениеЗаполнено(Стр.Номенклатура) Тогда
// Поиск в ТЧ другого документа через ссылку
МассиРезультатПоиска = Стр.НомерЗаказа.МатериальнаяСпецификация.НайтиСтроки(Новый Структура("Номенклатура", Стр.Номенклатура));
КонецЕсли;
КонецЦикла;
Проблема заключается в том, что в режиме совместимости 8.3.8 и выше механизмы работы с памятью и кэшированием объектов существенно изменились. Проанализируем основные причины, по которым поиск может возвращать пустой массив, даже если данные визуально присутствуют в таблице.
Это самая распространенная архитектурная ошибка, которая проявляется именно при смене платформы. Когда мы пишем Стр.НомерЗаказа.МатериальнаяСпецификация, платформа выполняет следующие действия:
НомерЗаказа.МатериальнаяСпецификация в память.НайтиСтроки().В новых версиях платформы обращение через точку внутри цикла может приводить к постоянному перечитыванию объекта. Если между итерациями цикла или из-за особенностей работы rphost кэш объекта обновляется некорректно, метод НайтиСтроки() может работать с «пустым» или неактуальным набором данных в памяти. Важный момент: индексы для быстрого поиска в коллекции строятся в момент обращения к ней. Если коллекция пересоздается динамически, индексы могут быть повреждены или не успеть инициализироваться.
Часто в структуре поиска используются поля с разными типами данных (например, Строка и СправочникСсылка). Рассмотрим уточненный вариант кода, который учитывает возможную пустоту значений:
// Рассмотрим пример безопасного формирования структуры поиска
Если Стр.НоменклатураИнтермех <> "" Тогда
Если ЗначениеЗаполнено(Стр.Номенклатура) Тогда
// Поиск по двум полям: строке и ссылке
ПараметрыОтбора = Новый Структура("НоменклатураИнтермех, Номенклатура", Стр.НоменклатураИнтермех, Стр.Номенклатура);
Иначе
// Поиск только по строке, если ссылка пустая
ПараметрыОтбора = Новый Структура("НоменклатураИнтермех", Стр.НоменклатураИнтермех);
КонецЕсли;
МассиРезультатПоиска = Стр.НомерЗаказа.МатериальнаяСпецификация.НайтиСтроки(ПараметрыОтбора);
КонецЕсли;
Выясним причину, по которой это может не сработать. В платформе 8.3 поиск по строковым полям стал более чувствителен к невидимым символам (неразрывные пробелы, переносы строк). Если в НоменклатураИнтермех в одном месте записана строка с пробелом в конце, а в другом — без него, НайтиСтроки() не сочтет их идентичными. В режиме совместимости 8.2 такие различия иногда игнорировались или обрабатывались иначе на уровне СУБД.
Если при попытке посмотреть значение в табло отладчика вы видите странное поведение (например, обращение к индексу [912] внезапно превращается в [91]), это явный признак нестабильности текущего релиза платформы или повреждения кэша метаданных. В версии 8.3.21.1624 были зафиксированы ошибки, связанные с некорректным отображением индексов коллекций в отладке, что может сбивать разработчика с толку, создавая иллюзию отсутствия данных.
Чтобы исключить влияние кэширования и постоянных обращений к базе через точку, проанализируем наиболее надежный способ решения задачи. Вместо поиска напрямую в табличной части документа-ссылки, необходимо один раз выгрузить данные в ТаблицаЗначений.
Рассмотрим правильный алгоритм:
// 1. Выгружаем спецификацию в ТЗ один раз до цикла
ТЗ_Спецификация = Стр.НомерЗаказа.МатериальнаяСпецификация.Выгрузить();
// 2. Теперь работаем с локальной копией данных в памяти
Для каждого Стр из Заявка Цикл
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Номенклатура", Стр.Номенклатура);
// Поиск по ТЗ работает стабильнее и быстрее
МассивРезультат = ТЗ_Спецификация.НайтиСтроки(ПараметрыОтбора);
// Обработка результатов...
КонецЦикла;
Этот подход гарантирует, что структура данных в памяти стабильна, а индексы поиска построены корректно и не сбрасываются при обращении к другим объектам.
Если поиск ведется по строковым полям (как НоменклатураИнтермех), крайне важно убедиться в отсутствии лишних пробелов. Посмотрим, как модифицировать код для повышения надежности:
// Принудительно обрезаем пробелы перед поиском
СтрокаПоиска = СокрЛП(Стр.НоменклатураИнтермех);
Если ЗначениеЗаполнено(СтрокаПоиска) Тогда
СтруктураПоиска = Новый Структура("НоменклатураИнтермех", СтрокаПоиска);
Результат = ТЗ_Спецификация.НайтиСтроки(СтруктураПоиска);
КонецЕсли;
Важно: Если колонка в табличной части имеет фиксированную длину, платформа будет дополнять её пробелами до конца длины. В этом случае поиск через Структура может требовать точного совпадения количества пробелов. Проверьте свойства колонки в конфигураторе.
Если код корректен, а НайтиСтроки() всё равно ведет себя неадекватно после смены режима совместимости, выполните следующие действия:
snccntx и reg_XXXX на сервере 1С (предварительно остановив службу rphost).Подводя итог, можно сказать, что проблема чаще всего кроется не в самом методе НайтиСтроки(), а в изменившемся механизме получения данных через точку от ссылки и особенностях работы кэша объектов в новых версиях 1С. Использование предварительной выгрузки данных в ТаблицаЗначений является «золотым стандартом» разработки, позволяющим избежать подобных проблем при любых обновлениях системы.