Как правильно организовать поиск данных в массиве на клиенте в 1С

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

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

Почему метод Массив.Найти() возвращает Неопределено

Проанализируем типовую ситуацию: на сервере формируется массив структур, содержащих поля Номенклатура и ТекстыСообщений. Затем на клиенте выполняется обход дерева элементов и попытка найти данные следующим образом:


Для каждого ЭлементДерева Из ЭлементыДерева Цикл
    ПараметрыОтбора = Новый Структура;
    ПараметрыОтбора.Вставить("Номенклатура", ТекущаяНоменклатура);
    НайденныеЗначения = СообщенияМассив.Найти(ПараметрыОтбора);
КонецЦикла;

В этом сценарии переменная НайденныеЗначения всегда будет принимать значение Неопределено. Выясним причину такого поведения платформы:

  1. Принцип работы метода Найти(): У объекта Массив метод Найти() принимает ровно одно значение и выполняет его поиск по строгому равенству элементов. Если в массив помещены структуры, метод ожидает точную ссылку на конкретный экземпляр структуры в памяти.
  2. Сравнение новых объектов: Конструкция Новый Структура создает в памяти совершенно новый объект. Платформа 1С сравнивает вновь созданный объект с элементами массива и не находит совпадений по ссылке, так как внутренние свойства и поля структуры при этом не анализируются.
  3. Производительность: Метод Найти() у массива осуществляет линейный перебор элементов со сложностью O(N). Если вызывать линейный поиск внутри рекурсивного обхода большого дерева, это приводит к квадратичной сложности и сильным зависаниям интерфейса.

Поскольку классическая ТаблицаЗначений недоступна в контексте &НаКлиенте, рассмотрим наиболее эффективные варианты решения этой задачи.

Вариант 1. Использование объекта Соответствие с массивом значений (рекомендуемый)

Если для одной позиции номенклатуры может существовать несколько сообщений или строк, оптимально использовать объект Соответствие, где ключом будет выступать ссылка на номенклатуру, а значением — массив связанных данных. Этот подход обеспечивает поиск за константное время O(1) и доступен как на сервере, так и на клиенте.

Рассмотрим формирование структуры на сервере:


&НаСервере
Функция ПодготовитьСообщенияНаСервере()
    СообщенияСоответствие = Новый Соответствие;
    
    // Предположим, СообщенияТЗ получена из параметров сеанса или запроса
    Для каждого СтрТЗ Из СообщенияТЗ Цикл
        СписокСообщений = СообщенияСоответствие[СтрТЗ.Номенклатура];
        Если СписокСообщений = Неопределено Тогда
            СписокСообщений = Новый Массив;
            СообщенияСоответствие.Вставить(СтрТЗ.Номенклатура, СписокСообщений);
        КонецЕсли;
        
        СписокСообщений.Добавить(СтрТЗ.ТекстыСообщений);
    КонецЦикла;
    
    Возврат СообщенияСоответствие;
КонецФункции

Теперь посмотрим, как просто и быстро выполняется получение данных на клиенте:


&НаКлиенте
Процедура ОбработатьДерево(ЭлементыДерева, СообщенияСоответствие)
    Для каждого ЭлементДерева Из ЭлементыДерева Цикл
        НайденныеСообщения = СообщенияСоответствие[ЭлементДерева.Номенклатура];
        Если НайденныеСообщения <> Неопределено Тогда
            Для каждого Текст Из НайденныеСообщения Цикл
                // Обработка полученных сообщений
            КонецЦикла;
        КонецЕсли;
        
        // Рекурсивный вызов для дочерних узлов
        ОбработатьДерево(ЭлементДерева.ПолучитьЭлементы(), СообщенияСоответствие);
    КонецЦикла;
КонецПроцедуры

Вариант 2. Использование ДанныеФормыКоллекция и метода НайтиСтроки()

Если необходимо сохранить табличную структуру с возможностью поиска по сложным фильтрам прямо на клиенте, можно поместить данные в реквизит формы типа ТаблицаЗначений. На клиенте этот реквизит преобразуется в тип ДанныеФормыКоллекция, у которого штатно доступен метод НайтиСтроки().

Разберем пример реализации:


&НаКлиенте
Процедура ПоискЧерезКоллекциюФормы(ЭлементыДерева)
    Для каждого ЭлементДерева Из ЭлементыДерева Цикл
        ПараметрыОтбора = Новый Структура("Номенклатура", ЭлементДерева.Номенклатура);
        НайденныеСтроки = ЭтаФорма.ТаблицаСообщений.НайтиСтроки(ПараметрыОтбора);
        
        Для каждого Стр Из НайденныеСтроки Цикл
            // Работа с найденными элементами коллекции
        КонецЦикла;
        
        ПоискЧерезКоллекциюФормы(ЭлементДерева.ПолучитьЭлементы());
    КонецЦикла;
КонецПроцедуры

Вариант 3. Подготовка и связывание данных на сервере

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

← На главную