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