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

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

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

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

В чем суть проблемы и почему возникает ошибка компоновки макета

Рассмотрим классическую ситуацию: разработчик подключается к внешней базе через COM-соединение, пытается программно добавить новый элемент отбора в компоновщик настроек и получает ошибку: «Ошибка компоновки макета. Ошибка в элементе отбора: глобальные элементы отбора обязательно должны использовать поля...».

При этом код создания отбора выглядит следующим образом:


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

Давайте проанализируем эту ситуацию. Почему платформа 1С выдает ошибку, несмотря на то, что объект вроде бы создается через COM-соединение?

Основной промах кроется в строке инициализации свойства ЛевоеЗначение. С помощью конструкции СоединениеВМС.NewObject("ОписаниеТипов", "ПолеКомпоновкиДанных").Типы().Получить(0) разработчик получает объект встроенного языка 1С с типом Тип (в данном случае тип самого поля компоновки данных). То есть в левую часть сравнения передается не конкретное поле («Номенклатура», «Склад» и т.д.), а просто описание метаданных типа.

Платформа при генерации макета компоновки данных ожидает увидеть в свойстве ЛевоеЗначение объект класса ПолеКомпоновкиДанных, инициализированный строковым путем к реквизиту схемы, а получает ссылку на COM-объект типа Тип. Отсюда и возникает конфликт компоновщика.

Правильный способ установки левого значения через COM

Чтобы исправить эту ошибку, нам нужно создать полноценный экземпляр объекта ПолеКомпоновкиДанных во внешней информационной базе и передать ему строковое имя поля в качестве параметра конструктора. Делается это непосредственно через метод NewObject нашего COM-соединения.

Давайте посмотрим на исправленный и полностью рабочий вариант кода:


// Шаг 1. Получаем коллекцию отборов из внешней базы через COM
ОтборКомпоновщика = КомпоновщикНастроекНастройкиВМС.Настройки.Отбор;

// Шаг 2. Добавляем новый элемент отбора. 
// Тип элемента отбора также получаем напрямую во внешней базе
ВидОбъекта = ОтборКомпоновщика.Элементы.Добавить(СоединениеВМС.NewObject("ОписаниеТипов", "ЭлементОтбораКомпоновкиДанных").Типы().Получить(0));

// Шаг 3. Задаем вид сравнения и активность отбора
ВидОбъекта.ВидСравнения = СоединениеВМС.ВидСравненияКомпоновкиДанных.ВИерархии;
ВидОбъекта.Использование = Истина;

// Шаг 4. ПРАВИЛЬНАЯ ИНИЦИАЛИЗАЦИЯ ЛЕВОГО ЗНАЧЕНИЯ
// Создаем во внешней базе объект "ПолеКомпоновкиДанных", передавая строковое имя поля
ВидОбъекта.ЛевоеЗначение = СоединениеВМС.NewObject("ПолеКомпоновкиДанных", "Номенклатура");

// Шаг 5. Задаем правое значение (в данном случае ссылку на элемент справочника из внешней базы)
ВидОбъекта.ПравоеЗначение = СоединениеВМС.Справочники.усНоменклатура.НайтиПоКоду("00000018354");

В данном случае строка СоединениеВМС.NewObject("ПолеКомпоновкиДанных", "Номенклатура") возвращает валидный COM-объект, содержащий указание на конкретное поле схемы компоновки данных. Платформа успешно сопоставляет его с полями набора данных и формирует корректный SQL-запрос.

Альтернативные и более надежные архитектурные подходы

Программная сборка отборов СКД «по кирпичикам» через COM-соединение — процесс кропотливый и потенциально нестабильный, особенно при обновлении версий платформы или конфигурации. Рассмотрим несколько лучших практик, которые позволяют решить данную задачу более элегантно.

Способ 1. Использование функций Библиотеки стандартных подсистем (БСП)

Если во внешней информационной базе внедрена БСП, вам не обязательно вручную создавать и типизировать объекты компоновщика. В общем модуле ОбщегоНазначенияКлиентСервер существует готовая функция ДобавитьЭлементКомпоновки, которая умеет корректно заполнять все необходимые свойства, включая типы полей.

Использование этого метода значительно сокращает код и снижает вероятность ошибок:


// Нам достаточно передать коллекцию настроек отбора, имя поля строкой и само значение сравнения
СоединениеВМС.ОбщегоНазначенияКлиентСервер.ДобавитьЭлементКомпоновки(
    КомпоновщикНастроекНастройкиВМС.Настройки.Отбор,
    "Номенклатура",
    СоединениеВМС.ВидСравненияКомпоновкиДанных.ВИерархии,
    СоединениеВМС.Справочники.усНоменклатура.НайтиПоКоду("00000018354")
);

Этот вызов автоматически создаст все необходимые объекты ПолеКомпоновкиДанных и ЭлементОтбораКомпоновкиДанных внутри контекста внешней базы без ручной манипуляции типами на стороне текущей сессии.

Способ 2. Сериализация настроек в XML (Самый надежный способ)

При передаче сложных структур через COM-границу могут возникать значительные задержки производительности, а также проблемы с преобразованием типов. Наиболее надежным и профессиональным подходом является полная подготовка настроек СКД в локальной базе и передача их во внешнюю базу в виде сериализованной XML-строки.

Разберем этот процесс по шагам:

  1. Создаем и полностью настраиваем структуру компоновщика в локальной базе (все отборы, группировки и параметры задаются привычными методами встроенного языка 1С без использования COM).
  2. Сериализуем готовые настройки в строку XML:

ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ЛокальныйКомпоновщикНастроек.Настройки, "settings", "http://v8.1c.ru/8.1/data-composition-system/settings");
СтрокаНастроекXML = ЗаписьXML.Закрыть();
  1. Передаем полученную строку СтрокаНастроекXML через COM-соединение во внешнюю базу.
  2. На стороне внешней базы десериализуем XML обратно в объект настроек СКД:

// Код выполняется с использованием контекста внешнего соединения СоединениеВМС
ЧтениеXML = СоединениеВМС.NewObject("ЧтениеXML");
ЧтениеXML.УстановитьСтроку(СтрокаНастроекXML);

// Восстанавливаем объект настроек во внешней базе
НастройкиДляВыгрузки = СоединениеВМС.СериализаторXDTO.ПрочитатьXML(ЧтениеXML, СоединениеВМС.Тип("НастройкиКомпоновкиДанных"));

Использование XML-сериализации полностью исключает проблемы несовместимости типов данных и делает код чистым, модульным и защищенным от изменений метаданных.

← На главную