Часто в практике разработчика 1С возникает задача построения отчета, который должен объединять данные из текущей базы с информацией из другой информационной базы (например, данные о путевых листах из УАТ и заказы из УТ). Самым распространенным инструментом для этого является использование COM-соединения и передача полученных данных в Систему компоновки данных (СКД) через Набор данных - объект.
Однако на этом пути программисты часто сталкиваются с проблемой: отчет формируется, но данные в колонках из внешней базы (например, показатели спидометра или веса) оказываются пустыми или связь между наборами данных не срабатывает. Разберем пошагово, как правильно реализовать этот механизм, избежав типичных ошибок.
Рассмотрим ситуацию: данные извлекаются через v82.Application (или COMConnector), помещаются в Таблицу Значений, которая затем передается в СКД. При попытке соединить данные по текстовому полю или ссылке отчет возвращает пустые строки. Проанализируем основные причины такого поведения:
COMObject), непосредственно в таблицу значений для СКД. СКД не умеет обращаться к свойствам COM-прокси объекта.Произвольный, что приводит к некорректной работе связей.СправочникСсылка.ФизическиеЛица) должен строго совпадать с типом поля в другом наборе.При получении данных из внешней базы мы получаем либо примитивные типы (числа, строки, даты), либо ссылки. Если нам нужно связать внешние данные с объектами текущей базы (например, найти того же водителя), необходимо преобразовать внешнюю ссылку в локальную.
Посмотрим на пример кода, который решает задачу преобразования внешней ссылки в локальную по наименованию:
// Создаем таблицу значений для передачи в СКД
ТЗ = Новый ТаблицаЗначений;
// Обязательно указываем типы колонок!
ТЗ.Колонки.Добавить("Водитель", Новый ОписаниеТипов("СправочникСсылка.ФизическиеЛица"));
ТЗ.Колонки.Добавить("СпидометрВыезда", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("СпидометрВозвращения", Новый ОписаниеТипов("Число"));
Пока Выборка.Следующий() Цикл
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.СпидометрВыезда = Выборка.СпидометрВыезда;
НоваяСтрока.СпидометрВозвращения = Выборка.СпидометрВозвращения;
// Получаем наименование из внешней базы (COM-объекта)
ИмяВодителя = String(Выборка.Водитель1.Description);
// Ищем соответствующую ссылку в локальной базе
НоваяСтрока.Водитель = Справочники.ФизическиеЛица.НайтиПоНаименованию(ИмяВодителя, Истина);
КонецЦикла;
Обратите внимание: при обращении к свойствам объекта через COM (например, Выборка.Водитель1.Description) важно приводить результат к строке через String(), чтобы разорвать связь с COM-объектом и получить чистые данные.
Использование метода НайтиПоНаименованию внутри цикла — это «антипаттерн», который сильно замедляет работу отчета, так как на каждой итерации происходит отдельный запрос к базе данных. Проанализируем более эффективный подход.
Рассмотрим, как оптимизировать этот процесс:
Соответствие, где ключом будет наименование, а значением — ссылка.Посмотрим на пример реализации:
// Собираем все имена
ВсеИмена = Новый Массив;
// ... (заполнение массива из внешней выборки)
// Находим ссылки разом
ЗапросЛокальный = Новый Запрос("ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.ФизическиеЛица ГДЕ Наименование В (&МассивИмен)");
ЗапросЛокальный.УстановитьПараметр("МассивИмен", ВсеИмена);
РезультатЛокальный = ЗапросЛокальный.Выполнить().Выгрузить();
КэшВодителей = Новый Соответствие;
Для Каждого Стр Из РезультатЛокальный Цикл
КэшВодителей.Вставить(Стр.Наименование, Стр.Ссылка);
КонецЦикла;
// В цикле по выборке COM просто берем из кэша
НоваяСтрока.Водитель = КэшВодителей.Получить(ИмяВодителя);
После того как таблица значений заполнена и локальные ссылки установлены, её необходимо передать в процессор компоновки данных. Выясним, как это сделать правильно в модуле объекта отчета.
Процедура ПриКомпоновкеРезультата(ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Получаем нашу ТЗ (методы описаны выше)
ВнешняяТЗ = ПолучитьДанныеИзВнешнейБазы();
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Помещаем таблицу в структуру внешних наборов
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТабВнешняя", ВнешняяТЗ);
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
КонецПроцедуры
Даже если программный код написан идеально, настройки в самом конструкторе СКД могут все испортить. Проанализируем настройки на вкладке «Связи наборов данных»:
НаборДанных1).ТабВнешняя).ВодительСсылка) и поле в приемнике (Водитель) имеют одинаковый тип.INNER JOIN).Важно: Если вы соединяете данные по строковому представлению (Наименованию), убедитесь, что в обоих наборах данных у этих полей в колонке Тип значения в СКД указана именно Строка с одинаковой длиной. Любое различие в пробелах или регистре сделает связь невозможной.
Если связь установилась (водитель отображается), но числовые колонки (спидометры) пусты, проверьте следующее:
ТаблицеЗначений (регистр имеет значение!).Игнорировать значения NULL или другие ограничения.Следуя этим рекомендациям, вы сможете стабильно передавать данные между базами 1С и корректно отображать их в сложных отчетах СКД.