При разработке сложных алгоритмов обработки данных в 1С:Предприятии программисты часто сталкиваются с ситуацией, когда код кажется логически верным, но при выполнении программа "проскакивает" цикл. В этой статье мы подробно разберем, почему массив, полученный методом НайтиСтроки, может оказаться пустым, проанализируем влияние длины строк на поиск и выясним, как правильно работать с деревьями значений на управляемых формах (на примере конфигурации БГУ 2.0).
Рассмотрим типичный фрагмент кода, в котором происходит подготовка данных для реестра документов. Программист копирует таблицу значений, сворачивает ее для получения уникальных записей и пытается найти соответствующие строки в исходной таблице для дальнейшей обработки.
Запрос2 = Запрос.Скопировать();
Запрос2.Свернуть("Контрагент, лицензия, Код, Договор","Сумма");
Запрос3 = Запрос2.Скопировать();
Запрос3.Свернуть("Код","Сумма");
Для каждого стр из Запрос3 цикл
НовСтр = _РеестрДокПОбНЛ.Добавить();
НовСтр.УИД = (Новый УникальныйИдентификатор);
НовСтр.КодОпер = стр.Код; // Здесь кроется потенциальная проблема
НовСтр.СумНеоблОпер = стр.Сумма;
// Пытаемся найти строки по коду
Запрос4 = Запрос2.НайтиСтроки(Новый Структура("Код", НовСтр.КодОпер));
Для Каждого Стр2 Из Запрос4 Цикл
// В этом месте цикл часто не отрабатывает
Сообщить(Стр2);
// ... дальнейшая логика заполнения дерева значений
КонецЦикла;
КонецЦикла;
Проанализируем ситуацию: первый цикл по Запрос3 отрабатывает корректно, однако второй цикл по коллекции Запрос4 полностью игнорируется. Это происходит потому, что метод НайтиСтроки возвращает пустой массив строк. Выясним причину этого поведения.
Самая коварная ошибка в 1С — это неявное ограничение длины строки в реквизитах таблиц значений. Если колонка таблицы КодОпер (в которую мы записываем значение) имеет тип Строка(7), а исходный стр.Код имеет длину 8 символов (например, "12345678"), произойдет следующее:
НовСтр.КодОпер = стр.Код; значение "12345678" превратится в "1234567".Запрос2.НайтиСтроки(Новый Структура("Код", "1234567")) система ищет точное совпадение в таблице Запрос2, где коды остались полными ("12345678").Важный совет: Всегда проверяйте длину строковых колонок в реквизитах формы или при программном создании таблиц через НовыеОписаниеТипов. Если вы работаете с кодами операций или артикулами, длина должна быть достаточной или неограниченной.
Еще один важный момент, который стоит проверить — это типы данных. Если в одной таблице код представлен как Число, а в другой как Строка, метод НайтиСтроки также вернет пустой результат. Платформа 1С строго сравнивает типы при поиске в коллекциях значений.
Проанализируем типы через отладчик:
ТипЗнч(стр.Код).ТипЗнч(НовСтр.КодОпер).
Если типы различаются, приведите их к одному виду перед поиском, используя функции Строка() или Число().
Когда мы работаем с большими объемами данных (например, формирование отчетности по НДС в БГУ 2.0), вложенные циклы с использованием НайтиСтроки могут значительно замедлить работу системы. Чтобы поиск выполнялся мгновенно, необходимо использовать индексацию.
Разберем, как добавить индекс для таблицы значений:
// Перед началом циклов добавим индексы для ускорения поиска
Запрос2.Индексы.Добавить("Код");
Запрос.Индексы.Добавить("Контрагент, Лицензия");
Индексы позволяют платформе не перебирать все строки таблицы каждый раз при вызове НайтиСтроки, а использовать подготовленную карту соответствий, что особенно важно при обработке тысяч контрагентов.
В тексте автора упоминается объект _ПредТипДог, который является деревом значений на управляемой форме. Часто новички сталкиваются с тем, что данные в коде заполняются, но на форме "ничего нет". Рассмотрим правильный алгоритм добавления строк в дерево:
// Сначала добавляем строку верхнего уровня
Стр_СведКАгент = _ПредТипДог.ПолучитьЭлементы().Добавить();
Стр_СведКАгент.НаимОрг = Стр2.Контрагент;
Стр_СведКАгент.ИННЮЛ = Стр2.Контрагент.ИНН;
// Добавляем подчиненную строку (второй уровень иерархии)
Запрос5 = Запрос.НайтиСтроки(Новый Структура("Контрагент, Лицензия", Стр2.Контрагент, Стр2.Лицензия));
Для Каждого Стр3 Из Запрос5 Цикл
// Обратите внимание: элементы добавляются ВНУТРЬ родительской строки
Стр_ДокПОбНЛ = Стр_СведКАгент.ПолучитьЭлементы().Добавить();
Стр_ДокПОбНЛ.СумОпер = Стр3.Сумма;
// Если нужно добавить третий уровень
Стр_НижнийУровень = Стр_ДокПОбНЛ.ПолучитьЭлементы().Добавить();
Стр_НижнийУровень.ТипДок = "Договор";
КонецЦикла;
Если данные все равно не отображаются, убедитесь, что:
Элементы._ПредТипДог.Развернуть(Стр_СведКАгент.ПолучитьИдентификатор(), Истина);.Проанализируем именование переменных в примере автора. Использование имен Запрос2, Запрос3 для таблиц значений является грубым нарушением стандартов разработки. Это путает других программистов, так как Запрос в 1С — это отдельный объект для работы с БД.
Рассмотрим, как правильно называть переменные:
Запрос2 используйте ТЗ_СвернутыеДанные.Запрос4 используйте НайденныеСтрокиПоКоду.Стр2 используйте СтрокаКонтрагента.Соблюдение этих правил поможет вам быстрее находить ошибки в логике, так как код станет самодокументированным. Проблема с обрезкой строки (7 против 8 символов) была бы замечена гораздо раньше, если бы переменные и колонки имели четкие, осмысленные названия.
Если ваш цикл по результату НайтиСтроки не выполняется, проверьте следующее:
СокрЛП())?Использование этих простых правил позволит вам избежать большинства "необъяснимых" ошибок при работе с коллекциями данных в 1С:Предприятии.