При разработке интерфейсов на платформе 1С:Предприятие 8.3 часто возникает задача отображения данных из связанных таблиц в одной ячейке динамического списка. Классический пример: в списке документов нужно показать все даты визитов или все номера телефонов контрагента, которые хранятся в отдельном регистре сведений. Поскольку динамический список строится на основе одного основного запроса, стандартное левое соединение приведет к дублированию строк основного объекта, что недопустимо для удобного интерфейса.
В этой статье мы подробно разберем несколько эффективных методов решения этой задачи, проанализируем их плюсы и минусы, а также научимся писать производительный код для работы с динамическими списками. Для расширения возможностей разработки также применимы практические методы доработки динамических списков и добавления новых полей.
Это самый гибкий и современный способ, который позволяет динамически «дорисовывать» данные в уже выбранные платформой строки. Основное преимущество метода заключается в том, что он работает только с теми данными, которые в данный момент отображаются на экране пользователя.
Важный нюанс: никогда не выполняйте запрос к базе данных в цикле внутри этого обработчика. Это приведет к катастрофическому падению производительности. Мы применим пакетную обработку.
Рассмотрим алгоритм реализации по шагам:
Строка, например, СписокДатТекстом.ПриПолученииДанныхНаСервере и создадим его обработчик.
&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
// 1. Собираем ссылки на документы из отображаемых строк
МассивСсылок = Строки.ПолучитьКлючи();
// 2. Одним запросом получаем все нужные даты из регистра сведений
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РегистрСведенийДаты.Документ КАК Ссылка,
| РегистрСведенийДаты.Дата КАК ДатаСобытия
|ИЗ
| РегистрСведений.РегистрСведенийДаты КАК РегистрСведенийДаты
|ГДЕ
| РегистрСведенийДаты.Документ В(&МассивСсылок)
|УПОРЯДОЧИТЬ ПО
| РегистрСведенийДаты.Дата";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Выборка = Запрос.Выполнить().Выбрать();
// 3. Группируем данные во временную структуру для удобного доступа
СоответствиеДанных = Новый Соответствие;
Пока Выборка.Следующий() Цикл
ТекСтрока = "";
Если СоответствиеДанных[Выборка.Ссылка] <> Неопределено Тогда
ТекСтрока = СоответствиеДанных[Выборка.Ссылка] + ", ";
КонецЕсли;
СоответствиеДанных.Вставить(Выборка.Ссылка, ТекСтрока + Формат(Выборка.ДатаСобытия, "ДФ=dd.MM.yyyy"));
КонецЦикла;
// 4. Заполняем данные в строках оформления
Для Каждого КлючИЗначение Из Строки Цикл
ДанныеСтроки = СоответствиеДанных[КлючИЗначение.Ключ];
Если ДанныеСтроки <> Неопределено Тогда
// Устанавливаем текст в нашу колонку
КлючИЗначение.Значение.Данные.СписокДатТекстом = ДанныеСтроки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем этот код: мы используем метод Строки.ПолучитьКлючи(), чтобы получить только те документы, которые видны пользователю. Затем мы делаем всего один запрос к БД и распределяем результат. Это обеспечивает высокую скорость работы интерфейса.
Если база данных содержит миллионы записей, а пользователи постоянно пользуются поиском и сортировкой по колонке со списком значений, то метод «на лету» может оказаться недостаточно быстрым. В этом случае мы рекомендуем использовать денормализацию.
Суть метода заключается в хранении уже готовой, склеенной строки непосредственно в объекте или вспомогательном регистре. Разберем ситуацию на примере документа и связанного с ним регистра.
Рассмотрим порядок действий:
ПредставлениеСпискаДат (тип Строка, неограниченной длины или достаточного размера).ПриЗаписи для регистра сведений, в котором хранятся ваши даты.
// В модуле подписки на событие
Процедура ОбновитьПредставлениеДатПриЗаписиРегистра(Источник, Отказ, Замещение)
// Источник - это НаборЗаписей регистра
ДокументСсылка = Источник.Отбор.Документ.Значение;
// Формируем строку дат (аналогично запросу из метода 1)
СтрокаДат = СформироватьСтрокуДатДляДокумента(ДокументСсылка);
// Записываем результат в документ
ОбъектДокумент = ДокументСсылка.ПолучитьОбъект();
ОбъектДокумент.ПредставлениеСпискаДат = СтрокаДат;
ОбъектДокумент.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры
Теперь в динамическом списке вам достаточно просто выбрать поле ПредставлениеСпискаДат. Это самый быстрый способ с точки зрения работы интерфейса, так как 1С просто читает готовую строку из таблицы документа.
Поскольку динамический список работает на механизме Системы компоновки данных (СКД), мы можем использовать возможности вычисляемых полей. Этот метод требует меньше кода, но может замедлять прокрутку списка. Для автоматизации этого процесса можно применить готовое решение для сборки значений колонки из нескольких строк в СКД.
Выясним, как это настроить:
Сервер, Вызов сервера и Внешнее соединение.
Функция ПолучитьСписокДатСтрокой(СсылкаНаДокумент) Экспорт
// Здесь выполняется запрос к регистру и возвращается соединенная строка
// Например: "01.01.2023, 05.01.2023"
КонецФункции
ИмяОбщегоМодуля.ПолучитьСписокДатСтрокой(Ссылка).Внимание: этот метод заставляет систему выполнять запрос для каждой строки отдельно. Используйте его только в небольших списках или если количество данных в регистре невелико.
Если ваши значения изначально находятся в разных полях одной строки (например, ДатаНачала и ДатаОкончания одного документа), вам не нужно писать код. Проанализируем возможности интерфейса:
Группировка в значение В ячейке.В результате значения из разных колонок будут отображаться в одной ячейке через пробел или с переносом строки, в зависимости от настроек высоты ячейки.
Мы проанализировали различные подходы к выводу нескольких значений. Подведем итоги выбора технологии:
Используя эти методы, вы сможете создавать профессиональные и информативные динамические списки, которые будут удобны пользователям и эффективны с точки зрения производительности системы 1С.