Как правильно передать список значений в параметры отчета СКД через COM-соединение?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

Работа с отчетами через COM-соединение — это классическая задача при интеграции различных баз 1С. Одной из самых частых трудностей, с которыми сталкиваются разработчики, является передача сложных типов данных, таких как СписокЗначений или Массив, в параметры схемы компоновки данных (СКД). Часто возникает ситуация, когда код кажется верным, соединение установлено, но отчет возвращает пустой результат. Разберем детально, как правильно реализовать этот механизм, и на что обратить внимание, чтобы избежать типичных ошибок.

Анализ механизма работы объектов через COM

Прежде чем переходить к коду, проанализируем фундаментальное правило работы COM-соединения в 1С: объект считается «своим» только тогда, когда он создан в контексте того же самого соединения. Если мы создадим СписокЗначений в текущей базе и попытаемся передать его в метод внешней базы через COM, внешняя база не сможет распознать его как корректный объект 1С. Она увидит его как универсальный COMОбъект, который нельзя напрямую использовать в запросе или фильтре СКД.

Рассмотрим выдержку из технической документации, которая объясняет это поведение: если 1С:Предприятие получает объект типа VT_DISPATCH, оно преобразует его в COMОбъект. Но если объект был создан тем же самым экземпляром соединения, 1С «узнает» его и позволит работать с ним как с родным типом. Именно поэтому для создания коллекций значений (массивов, списков) мы должны использовать метод NewObject() самого COM-соединения.

Шаг 1: Установка соединения и инициализация схемы

Начнем с инициализации подключения и получения макета отчета. Предположим, мы подключаемся к базе ЗУП для получения данных по подразделениям. Посмотрим на пример кода:


// Устанавливаем соединение с внешней базой
ЗУП = ПодключениеComС("ПутьКБазе", "Логин", "Пароль"); 

// Получаем схему компоновки из внешнего отчета
СхемаКомпоновкиДанных = ЗУП.Отчеты.Отчет1.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");

// Инициализируем компоновщик настроек во внешней базе
КомпоновщикНастроекНастройки = ЗУП.NewObject("КомпоновщикНастроекКомпоновкиДанных");
ИсточникДоступныхНастроек = ЗУП.NewObject("ИсточникДоступныхНастроекКомпоновкиДанных", СхемаКомпоновкиДанных);
КомпоновщикНастроекНастройки.Инициализировать(ИсточникДоступныхНастроек);

Шаг 2: Создание коллекции значений во внешнем контексте

Выясним причину, почему обычное создание списка значений в нашей базе не сработает. Нам необходимо, чтобы список содержал ссылки, понятные для удаленной базы. Для этого мы выполняем запрос во внешней базе, получаем результат и заполняем список, созданный через ЗУП.NewObject("СписокЗначений").


// Загружаем настройки по умолчанию
КомпоновщикНастроекНастройки.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
Настройки = КомпоновщикНастроекНастройки.ПолучитьНастройки();

// Формируем список подразделений во внешней базе
Запрос = ЗУП.NewObject("Запрос"); 
Запрос.Текст = 
"ВЫБРАТЬ
|	ПодразделенияОрганизаций.Ссылка КАК Подразделение
|ИЗ
|	Справочник.ПодразделенияОрганизаций КАК ПодразделенияОрганизаций";

РезультатЗапроса = Запрос.Выполнить().Выгрузить();
СписокПодразделений = ЗУП.NewObject("СписокЗначений");

Для Каждого Строка Из РезультатЗапроса Цикл
    // Добавляем ссылку, которая уже является COM-объектом удаленной базы
    СписокПодразделений.Добавить(Строка.Подразделение);
КонецЦикла;

Важный нюанс: Если вы планируете передавать ссылки по их коду или наименованию, используйте методы поиска удаленной базы, например: ЗУП.Справочники.ПодразделенияОрганизаций.НайтиПоКоду("001"). Это гарантирует, что в параметр попадет объект, который удаленная СКД сможет сопоставить со своими данными.

Шаг 3: Установка параметров и главная ловушка компоновщика

Теперь рассмотрим момент, где чаще всего совершается ошибка. После того как мы получили объект Настройки и установили в нем параметр, мы должны использовать именно этот измененный объект при генерации макета. Проанализируем типичную ошибку:


// Устанавливаем значение параметра
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("СписокПодразделений", СписокПодразделений);

// ОШИБКА: Использование КомпоновщикНастроекНастройки.Настройки вместо переменной Настройки
// КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроекНастройки.Настройки...); 

// ПРАВИЛЬНО: Передаем объект Настройки, в котором мы реально меняли параметры
КомпоновщикМакета = ЗУП.NewObject("КомпоновщикМакетаКомпоновкиДанных");
МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, , , 
    ЗУП.NewObject("ОписаниеТипов", "ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений").Типы().Получить(0));

Разберем подробнее: когда мы вызываем КомпоновщикНастроек.ПолучитьНастройки(), мы создаем копию текущих настроек. Изменяя параметры в этой копии (переменная Настройки), мы не меняем состояние самого КомпоновщикНастроекНастройки.Настройки автоматически. Поэтому при вызове КомпоновщикМакета.Выполнить необходимо передавать именно тот объект, в котором были произведены изменения.

Шаг 4: Вывод результата

Завершающим этапом является инициализация процессора компоновки и вывод данных. Поскольку мы работаем через COM, результат удобнее всего выгружать в ТаблицуЗначений, созданную также на стороне внешней базы, чтобы затем передать её обратно в нашу информационную систему.


ПроцессорКомпоновкиДанных = ЗУП.NewObject("ПроцессорКомпоновкиДанных");
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных);

ПроцессорВывода = ЗУП.NewObject("ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений");
ДанныеТЗ = ЗУП.NewObject("ТаблицаЗначений");
ПроцессорВывода.УстановитьОбъект(ДанныеТЗ);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);

// Теперь ДанныеТЗ содержит результат выполнения отчета с учетом переданных фильтров

Дополнительные рекомендации для стабильной работы

Проанализируем альтернативные способы передачи данных, если стандартный СписокЗначений через COM работает нестабильно (например, при специфических настройках прав или использовании 64-разрядного сервера с 32-разрядными компонентами):

  1. Использование Массива вместо Списка значений. Массивы являются более простыми структурами данных и часто быстрее передаются через границы процессов COM. В СКД условие В (&Параметр) одинаково хорошо работает как со списком, так и с массивом.
  2. Передача через Уникальные Идентификаторы (GUID). Если вы сомневаетесь в корректности передачи ссылок, можно передать массив строк, содержащих UUID подразделений. На стороне внешней базы в коде или прямо в тексте запроса СКД можно преобразовать эти строки обратно в ссылки, используя метод ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаGUID)).
  3. Сериализация данных. Для очень сложных структур можно использовать сериализацию в XML или JSON. Вы превращаете список параметров в строку на своей стороне, передаете её как один текстовый параметр через COM, а на удаленной стороне (внутри экспортной функции) десериализуете её обратно в объекты 1С.
  4. Проверка типов. Всегда проверяйте, что тип данных в схеме СКД (на закладке "Параметры") совпадает с типом передаваемого значения. Если в СКД указан тип СправочникСсылка.ПодразделенияОрганизаций, а вы передаете СписокЗначений, не забудьте убедиться, что в настройках параметра в самой схеме разрешено использование списка (флаг "Доступен список значений").

Таким образом, успех передачи параметров через COM зависит от двух факторов: создания объектов коллекций в контексте внешней базы и правильного использования переменных настроек при компоновке макета. Соблюдение этих правил позволит вам эффективно использовать мощь СКД при работе с распределенными базами данных.

← На главную