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