При разработке сложных отчетов на базе Системы компоновки данных (СКД) (в том числе и в сценариях, где применяется Пользовательская СКД) программисты часто сталкиваются с ситуацией, когда источником данных выступает внешняя ТаблицаЗначений, сформированная программно. Это классический пример работы, требующий оптимизации отчетов с набором данных - объект. Одной из специфических задач является вывод содержимого колонки, в которой хранятся объекты типа Массив, в виде одной текстовой строки, где элементы перечислены через запятую. Рассмотрим, почему стандартные методы могут не сработать, и разберем проверенные способы решения этой задачи.
Давайте проанализируем ситуацию. Типовая агрегатная функция СКД СоединитьСтроки() предназначена для того, чтобы собрать значения колонки из нескольких строк выборки. Когда мы передаем в СКД таблицу значений, в которой одна из колонок содержит Массив, система воспринимает этот массив как единый объект внутри одной записи. Для функции СоединитьСтроки() это не перечень элементов, а один неделимый блок данных. Именно поэтому попытка прописать в ресурсах СоединитьСтроки(ИмяКолонки, ",") зачастую не приводит к желаемому результату или вызывает ошибку компоновки.
Для решения этой проблемы мы можем пойти тремя путями: подготовить данные заранее, использовать возможности вычисляемых полей или преобразовать структуру данных во вложенную таблицу. Разберем каждый из этих методов подробнее.
Самый простой и производительный способ — это подготовить строку из массива еще до того, как таблица будет передана в СКД. Это избавит нас от необходимости писать сложные выражения в самой схеме компоновки. Рассмотрим, как это реализовать в процедуре ПриКомпоновкеРезультата.
Предположим, у нас есть таблица значений ТЗ_Данные с колонкой МассивДокументов. Проанализируем пример кода для преобразования этой колонки:
// Создаем новую колонку для строкового представления
ТЗ_Данные.Колонки.Добавить("СписокДокументовСтрокой", Новый ОписаниеТипов("Строка"));
Для Каждого СтрокаТЗ Из ТЗ_Данные Цикл
// Используем встроенную функцию СтрСоединить для быстрой сборки строки
СтрокаТЗ.СписокДокументовСтрокой = СтрСоединить(СтрокаТЗ.МассивДокументов, ", ");
КонецЦикла;
// Передаем подготовленную таблицу в СКД
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТаблицаСписка", ТЗ_Данные);
После такой обработки нам достаточно просто выбрать поле СписокДокументовСтрокой в настройках отчета. Этот метод хорош тем, что мы полностью контролируем формат строки и не нагружаем процессор компоновки данных лишними вычислениями.
Если по каким-то причинам мы не хотим менять структуру исходной таблицы или нам нужно гибко управлять выводом строки непосредственно в СКД, воспользуемся Вычисляемыми полями и внешними функциями. Это позволит нам вызывать код 1С прямо из выражения компоновки. Данный подход концептуально похож на то, как реализуется склейка нескольких картинок в одну средствами 1С, только вместо изображений мы обрабатываем текстовые данные.
Выясним последовательность действий:
РаботаСОтчетамиСервер).
Функция ПолучитьПредставлениеМассива(ПереданныйМассив) Экспорт
Если ТипЗнч(ПереданныйМассив) <> Тип("Массив") Тогда
Возврат Строка(ПереданныйМассив);
КонецЕсли;
Результат = "";
Для Каждого Элемент Из ПереданныйМассив Цикл
Результат = Результат + ?(Результат = "", "", ", ") + Строка(Элемент);
КонецЦикла;
Возврат Результат;
КонецФункции
Теперь перейдем в СКД на закладку "Вычисляемые поля" и добавим новое поле. В колонке Выражение вызовем нашу функцию:
РаботаСОтчетамиСервер.ПолучитьПредставлениеМассива(ИмяКолонкиСМассивом)
Важный момент: убедитесь, что в свойствах набора данных тип колонки ИмяКолонкиСМассивом указан верно (как правило, это Произвольный), иначе СКД может не передать объект в функцию корректно.
Если мы хотим использовать именно штатную функцию СоединитьСтроки(), нам нужно представить данные массива как вложенную таблицу внутри каждой строки основной таблицы. СКД умеет работать с типом данных ТаблицаЗначений внутри ячейки как с набором строк.
Разберем этот подход: в исходной таблице значений вместо массива мы создаем для каждой строки маленькую ТаблицуЗначений с одной колонкой (например, Значение). В этом случае в СКД мы сможем обратиться к данным так:
СоединитьСтроки(ИмяВложеннойТаблицы.Значение, ", ")
Такой метод сложнее в реализации и обычно используется, когда нужно не просто перечислить значения, а применить к ним дополнительные условия оформления или группировки средствами компоновки. В особо сложных случаях архитектурно это может быть даже сопоставимо с решением использовать две разных схемы в отчете СКД, но в рамках одной схемы вложенные таблицы — рабочий инструмент.
Когда мы успешно соединили элементы массива в одну длинную строку, возникает вопрос визуального представления. Если в массиве много элементов, ячейка в отчете может стать слишком широкой или текст будет обрезан.
Проанализируем настройки оформления:
Для окончательной шлифовки внешнего вида отчета иногда требуется не только работа с шириной колонок, но и программное изменение заголовка группировки отчета СКД, чтобы заголовки соответствовали динамическому содержимому.
Резюме: Несмотря на то что СКД не умеет "из коробки" перебирать элементы массива в ячейке через агрегатные функции, использование предварительной подготовки данных в коде (Способ 1) или вызов функций общего модуля (Способ 2) полностью решает эту задачу. Рассмотрим выбор метода исходя из сложности отчета: для простых списков лучше подготовить строку заранее, для сложных интерактивных отчетов — использовать вычисляемые поля.