При разработке обработок на обычных формах 1С программисты часто сталкиваются с ситуацией, когда результат сложного поиска не отображается в табличном поле полностью. Вместо ожидаемого списка позиций в таблице красуется лишь одна — последняя найденная строка. Давайте подробно разберем, почему так происходит, проанализируем ошибки в архитектуре кода и выясним, как правильно реализовать поиск с учетом специфических символов (например, азербайджанского алфавита) и высокой производительности.
Первая и самая очевидная причина, по которой выводится только одна строка, кроется в использовании оператора присваивания внутри цикла. Рассмотрим фрагмент проблемного кода:
Пока ВыборкаДетальныеЗаписи.Следующий цикл
Результат = Запрос.Выполнить.Выгрузить;
ЭлементыФормы.ТЗ.Значение = Результат;
ЭлементыФормы.ТЗ.СоздатьКолонки;
КонецЦикла;
Проанализируем ситуацию: на каждой итерации цикла переменной Результат присваивается новая таблица значений. Затем строка ЭлементыФормы.ТЗ.Значение = Результат полностью заменяет старое содержимое элемента формы новым. В итоге, когда цикл завершается, в таблице остается только то, что было получено на самом последнем шаге. Помните: прямое присваивание таблицы к значению элемента формы — это полная замена данных, а не их добавление.
Кроме того, вызов метода СоздатьКолонки внутри цикла — это избыточная операция, которая заставляет интерфейс перерисовываться при каждом проходе, что существенно замедляет работу программы.
Вторая критическая ошибка в представленном коде — выполнение Запрос.Выполнить() внутри цикла по другой выборке. Если в вашем справочнике Номенклатура содержится 10 000 записей, система выполнит 10 000 отдельных обращений к базе данных. Это классический пример «антипаттерна», который может привести к зависанию всей системы или критической нагрузке на SQL-сервер.
Для оптимизации мы должны стремиться к тому, чтобы выполнить один запрос к базе, передав в него все необходимые параметры сразу, либо обработать данные в оперативной памяти, если объем позволяет.
Если вам необходимо выводить данные порциями в процессе обработки, нужно не присваивать таблицу целиком, а добавлять строки в уже существующую структуру. Давайте выясним, как это реализовать правильно:
// 1. Создаем структуру таблицы один раз перед началом цикла
ТаблицаРезультатов = Новый ТаблицаЗначений;
ТаблицаРезультатов.Колонки.Добавить("Ссылка");
ТаблицаРезультатов.Колонки.Добавить("Группа");
ТаблицаРезультатов.Колонки.Добавить("Наименование");
// ... в цикле обработки ...
Пока Выборка.Следующий() Цикл
// Выполняем поиск или трансформацию данных
// ...
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
ВыборкаПоиска = РезультатЗапроса.Выбрать();
Пока ВыборкаПоиска.Следующий() Цикл
НоваяСтрока = ТаблицаРезультатов.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ВыборкаПоиска);
КонецЦикла;
КонецЕсли;
КонецЦикла;
// 2. И только после завершения всех циклов привязываем результат к форме
ЭлементыФормы.ТЗ.Значение = ТаблицаРезультатов;
ЭлементыФормы.ТЗ.СоздатьКолонки();
В исходной задаче требовалось учитывать замены символов азербайджанского алфавита (например, e на ə). Вместо того чтобы мучить базу данных постоянными запросами с разными параметрами ПОДОБНО, мы можем применить следующий алгоритм:
СтрЗаменить) создадим в этой таблице дополнительную колонку «НормализованноеНаименование».Рассмотрим пример эффективной очистки строки от цифр и замены символов:
Функция НормализоватьСтроку(Знач ВходнаяСтрока)
// Заменяем азербайджанские символы
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "e", "ə");
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, "E", "Ə");
// Очистка от цифр (можно использовать RegExp для ускорения)
Цифры = "0123456789";
Для Индекс = 1 По СтрДлина(Цифры) Цикл
ВходнаяСтрока = СтрЗаменить(ВходнаяСтрока, Сред(Цифры, Индекс, 1), "");
КонецЦикла;
Возврат НРег(СокрЛП(ВходнаяСтрока));
КонецФункции
Самый быстрый способ решения задачи «поиска по списку вариантов» — это передача таблицы всех вариантов написания в запрос. Проанализируем, как это сделать:
Запрос как параметр.В.Посмотрим на пример кода, объединяющий эти принципы:
Процедура ВыполнитьПоискПоВсемВариантам()
// Создаем таблицу с вариантами написания
ТЗВарианты = Новый ТаблицаЗначений;
ТЗВарианты.Колонки.Добавить("ВариантНаименования", Новый ОписаниеТипов("Строка"));
// Заполняем таблицу (здесь ваша логика замен)
// НоваяЗапись = ТЗВарианты.Добавить();
// НоваяЗапись.ВариантНаименования = "...";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Варианты.ВариантНаименования КАК Название
|ПОМЕСТИТЬ ВТ_Искомые
|ИЗ
| &ТЗВарианты КАК Варианты
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование В (ВЫБРАТЬ Название ИЗ ВТ_Искомые)";
Запрос.УстановитьПараметр("ТЗВарианты", ТЗВарианты);
Результат = Запрос.Выполнить().Выгрузить();
ЭлементыФормы.ТЗ.Значение = Результат;
ЭлементыФормы.ТЗ.СоздатьКолонки();
КонецПроцедуры
Работая с ЭлементыФормы, не забывайте о комфорте пользователя. Если данных много:
ЭлементыФормы.ТЗ.ОбновитьСтроки() только после окончания заполнения.ЭтаФорма.ОбновлениеОтображения(), если производите массовые манипуляции с интерфейсом.Предупреждение с таймаутом лучше использовать Состояние() — это не блокирует поток выполнения и выглядит профессиональнее.Таким образом, для исправления вашей проблемы достаточно вынести код заполнения таблицы за пределы цикла, использовать один общий запрос и не забывать про метод Загрузить() или постепенное наполнение через Добавить(). Это не только решит проблему с отображением одной строки, но и ускорит работу вашей обработки в десятки раз.