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

Программист 1С v8.3 (Обычные формы) Управленческий учет
← На главную

Часто в практике разработчика 1С возникает задача построения отчета, который должен объединять данные из текущей базы с информацией из другой информационной базы (например, данные о путевых листах из УАТ и заказы из УТ). Самым распространенным инструментом для этого является использование COM-соединения и передача полученных данных в Систему компоновки данных (СКД) через Набор данных - объект.

Однако на этом пути программисты часто сталкиваются с проблемой: отчет формируется, но данные в колонках из внешней базы (например, показатели спидометра или веса) оказываются пустыми или связь между наборами данных не срабатывает. Разберем пошагово, как правильно реализовать этот механизм, избежав типичных ошибок.

Анализ проблемы: почему данные не выводятся?

Рассмотрим ситуацию: данные извлекаются через v82.Application (или COMConnector), помещаются в Таблицу Значений, которая затем передается в СКД. При попытке соединить данные по текстовому полю или ссылке отчет возвращает пустые строки. Проанализируем основные причины такого поведения:

  1. Использование COM-объектов вместо ссылок: Нельзя передавать «живую» ссылку, полученную через COM (объект типа COMObject), непосредственно в таблицу значений для СКД. СКД не умеет обращаться к свойствам COM-прокси объекта.
  2. Отсутствие типизации колонок: Если колонки таблицы значений не типизированы явно, СКД может назначить им тип Произвольный, что приводит к некорректной работе связей.
  3. Несоответствие типов при связи: Тип поля в одном наборе данных (например, СправочникСсылка.ФизическиеЛица) должен строго совпадать с типом поля в другом наборе.

Шаг 1. Получение данных и преобразование COM-объектов

При получении данных из внешней базы мы получаем либо примитивные типы (числа, строки, даты), либо ссылки. Если нам нужно связать внешние данные с объектами текущей базы (например, найти того же водителя), необходимо преобразовать внешнюю ссылку в локальную.

Посмотрим на пример кода, который решает задачу преобразования внешней ссылки в локальную по наименованию:


// Создаем таблицу значений для передачи в СКД
ТЗ = Новый ТаблицаЗначений;
// Обязательно указываем типы колонок!
ТЗ.Колонки.Добавить("Водитель", Новый ОписаниеТипов("СправочникСсылка.ФизическиеЛица"));
ТЗ.Колонки.Добавить("СпидометрВыезда", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("СпидометрВозвращения", Новый ОписаниеТипов("Число"));

Пока Выборка.Следующий() Цикл
    НоваяСтрока = ТЗ.Добавить();
    НоваяСтрока.СпидометрВыезда = Выборка.СпидометрВыезда;
    НоваяСтрока.СпидометрВозвращения = Выборка.СпидометрВозвращения;
    
    // Получаем наименование из внешней базы (COM-объекта)
    ИмяВодителя = String(Выборка.Водитель1.Description); 
    
    // Ищем соответствующую ссылку в локальной базе
    НоваяСтрока.Водитель = Справочники.ФизическиеЛица.НайтиПоНаименованию(ИмяВодителя, Истина);
КонецЦикла;

Обратите внимание: при обращении к свойствам объекта через COM (например, Выборка.Водитель1.Description) важно приводить результат к строке через String(), чтобы разорвать связь с COM-объектом и получить чистые данные.

Шаг 2. Оптимизация поиска объектов

Использование метода НайтиПоНаименованию внутри цикла — это «антипаттерн», который сильно замедляет работу отчета, так как на каждой итерации происходит отдельный запрос к базе данных. Проанализируем более эффективный подход.

Рассмотрим, как оптимизировать этот процесс:

  1. Сначала выгрузим все уникальные наименования из внешней выборки в массив.
  2. Одним запросом найдем все ссылки в текущей базе.
  3. Поместим их в Соответствие, где ключом будет наименование, а значением — ссылка.

Посмотрим на пример реализации:


// Собираем все имена
ВсеИмена = Новый Массив;
// ... (заполнение массива из внешней выборки)

// Находим ссылки разом
ЗапросЛокальный = Новый Запрос("ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.ФизическиеЛица ГДЕ Наименование В (&МассивИмен)");
ЗапросЛокальный.УстановитьПараметр("МассивИмен", ВсеИмена);
РезультатЛокальный = ЗапросЛокальный.Выполнить().Выгрузить();

КэшВодителей = Новый Соответствие;
Для Каждого Стр Из РезультатЛокальный Цикл
    КэшВодителей.Вставить(Стр.Наименование, Стр.Ссылка);
КонецЦикла;

// В цикле по выборке COM просто берем из кэша
НоваяСтрока.Водитель = КэшВодителей.Получить(ИмяВодителя);

Шаг 3. Передача таблицы в СКД

После того как таблица значений заполнена и локальные ссылки установлены, её необходимо передать в процессор компоновки данных. Выясним, как это сделать правильно в модуле объекта отчета.


Процедура ПриКомпоновкеРезультата(ДанныеРасшифровки, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    
    // Получаем нашу ТЗ (методы описаны выше)
    ВнешняяТЗ = ПолучитьДанныеИзВнешнейБазы();
    
    СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    // Помещаем таблицу в структуру внешних наборов
    ВнешниеНаборыДанных = Новый Структура;
    ВнешниеНаборыДанных.Вставить("ТабВнешняя", ВнешняяТЗ);
    
    ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
КонецПроцедуры

Важные нюансы настройки связей в СКД

Даже если программный код написан идеально, настройки в самом конструкторе СКД могут все испортить. Проанализируем настройки на вкладке «Связи наборов данных»:

Важно: Если вы соединяете данные по строковому представлению (Наименованию), убедитесь, что в обоих наборах данных у этих полей в колонке Тип значения в СКД указана именно Строка с одинаковой длиной. Любое различие в пробелах или регистре сделает связь невозможной.

Почему пропадали числовые данные (спидометры)?

Если связь установилась (водитель отображается), но числовые колонки (спидометры) пусты, проверьте следующее:

  1. Имена полей: В наборе данных «Объект» имена полей должны строго совпадать с именами колонок в вашей ТаблицеЗначений (регистр имеет значение!).
  2. Роли полей: Проверьте на вкладке «Наборы данных», не установлена ли для числовых полей роль Игнорировать значения NULL или другие ограничения.
  3. Ресурс: Если вы хотите видеть итоги по спидометрам, не забудьте добавить эти поля на вкладку «Ресурсы».

Следуя этим рекомендациям, вы сможете стабильно передавать данные между базами 1С и корректно отображать их в сложных отчетах СКД.

← На главную