При переводе функционала со стандартных (обычных) форм на управляемые разработчики часто сталкиваются с ошибками при попытке работать с выборками данных на стороне клиента или сохранить их в реквизитах формы. Рассмотрим, почему возникает эта проблема, какие платформенные ограничения действуют в управляемом приложении и как правильно переписать алгоритм поиска и анализа данных.
Проанализируем архитектурные ограничения платформы 1С:Предприятие 8.3:
СправочникВыборка (как и ВыборкаИзРезультатаЗапроса) доступен исключительно на стороне сервера, в толстом клиенте или во внешнем соединении. Тонкий клиент и веб-клиент не имеют доступа к этому типу данных.ДанныеФормыКоллекция, ДанныеФормыДерево, ДанныеФормыСтруктура). Объект выборки не сериализуется и не может передаваться через границу клиент-сервер.Новый РеквизитФормы с указанием типа СправочникВыборка завершится ошибкой во время выполнения метода ИзменитьРеквизиты(), так как платформа не поддерживает хранение динамических выборок в контексте формы.Выясним причину неэффективности исходного кода: считывание всех элементов справочника методом Выбрать() и передача промежуточных данных на клиент перегружают сеть и память. В управляемом интерфейсе всю обработку информации следует выполнять на стороне сервера, возвращая на форму только готовый результат.
Разберем по шагам правильный алгоритм рефакторинга:
Выбрать() считывает из базы абсолютно все поля объектов. Используем объект Запрос, чтобы выбрать только необходимые поля (например, Ссылка, Код, Наименование) и при возможности ограничить выборку условием ГДЕ.ТаблицаЗначений, который на сервере заполняется с помощью метода ЗначениеВРеквизитФормы() или прямым заполнением строк коллекции ДанныеФормыКоллекция.ПриОткрытии переносим первичный расчет в обработчик ПриСозданииНаСервере, что исключает лишние клиент-серверные вызовы.Посмотрим на пример правильной организации серверной процедуры поиска дубликатов без использования выборки на клиенте:
&НаСервере
Процедура ПроверитьДубликатыНаСервере(ИмяСправочника, ПроверяемоеНаименование, ТекущаяСсылка)
// Очищаем таблицу результатов на форме
ТаблицаПохожихЗначений.Очистить();
// Используем запрос для получения только нужных полей
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Спр.Ссылка КАК Ссылка,
| Спр.Код КАК Код,
| Спр.Наименование КАК Наименование
|ИЗ
| Справочник." + ИмяСправочника + " КАК Спр
|ГДЕ
| Спр.Ссылка <> &ТекущаяСсылка
| И НЕ Спр.ПометкаУдаления";
Запрос.УстановитьПараметр("ТекущаяСсылка", ТекущаяСсылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
ЭталонСтрока = ВРег(СокрЛП(ПроверяемоеНаименование));
Пока Выборка.Следующий() Цикл
СравниваемаяСтрока = ВРег(СокрЛП(Выборка.Наименование));
// Проверка на точный дубликат
Если СравниваемаяСтрока = ЭталонСтрока Тогда
ВызватьИсключение "В справочнике уже имеется элемент с наименованием """ + ПроверяемоеНаименование + """ (Код: " + Выборка.Код + ")";
КонецЕсли;
// Вычисление процента совпадения через серверную функцию
Процент = ВспомФункцииУФСервер.НечеткоеСравнениеСтрок(СравниваемаяСтрока, ЭталонСтрока);
Если Процент > 60 Тогда
НоваяСтрока = ТаблицаПохожихЗначений.Добавить();
НоваяСтрока.Ссылка = Выборка.Ссылка;
НоваяСтрока.Код = Выборка.Код;
НоваяСтрока.Наименование = Выборка.Наименование;
НоваяСтрока.ПроцентСовпадения = Процент;
КонецЕсли;
КонецЦикла;
// Сортировка таблицы на форме
ТаблицаПохожихЗначений.Сортировать("ПроцентСовпадения Убыв");
КонецПроцедуры
Рассмотрим подробнее альтернативные механизмы платформы и типовых конфигураций, которые позволяют избежать перебора всех элементов справочника вручную:
ПолнотекстовыйПоиск.СоздатьСписок() с использованием оператора нечеткости ~ выполняет поиск похожих строк средствами СУБД по предварительно построенному индексу, что работает значительно быстрее цикла по всей таблице.