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

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

При работе с внешними информационными базами 1С через COM-соединение разработчики часто сталкиваются с ошибкой «Несоответствие типов (параметр №1)» при вызове метода Выбрать() у объекта РезультатЗапроса. Ошибка возникает в тот момент, когда требуется выполнить обход по группировкам или иерархии, передав соответствующий режим обхода.

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

Причина ошибки «Несоответствие типов» при работе через COM

Проанализируем ситуацию с несовместимостью типов данных. В платформе 1С:Предприятие системные перечисления (такие как ОбходРезультатаЗапроса, РежимПроведения и другие), а также объекты метаданных и ссылки принадлежат контексту конкретной информационной базы.

Когда мы выполняем следующий код в текущей (локальной) базе:

Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Перечисление ОбходРезультатаЗапроса.ПоГруппировкам берется из локального контекста текущего сеанса. Однако сам объект РезультатЗапроса был получен из внешнего COM-соединения. Для объекта внешней базы локальное перечисление является чужеродным типом. Попытка передать его в метод внешнего объекта приводит к ошибке несоответствия типов в параметре №1.

Эта же проблема возникнет и при передаче ссылочных параметров во внешний запрос через метод УстановитьПараметр(). Нельзя передавать ссылку или массив ссылок из текущей базы во внешний запрос. Все ссылочные объекты и перечисления должны быть получены непосредственно из внешней базы (например, через Соединение.Справочники... НайтиПоКоду()) или передаваться в виде примитивных типов (числа, строки, даты, булево).

Решение проблемы: обращение к перечислениям через объект COM-соединения

Рассмотрим подробнее решение проблемы. Для того чтобы платформой корректно воспринимался параметр режима обхода выборки, системное перечисление необходимо запрашивать непосредственно из контекста подключенного COM-объекта.

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

  1. Инициализируем COM-соединение:
    
    Коннектор = Новый COMObject("V83.COMConnector");
    Попытка
        Соединение = Коннектор.Connect("File=""C:\Bases\RemoteBase"";Usr=""Admin"";Pwd=""123"";");
    Исключение
        Сообщить("Не удалось подключиться к внешней ИБ: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
  2. Создаем и выполняем запрос во внешней базе:
    
    ЗапросВнешний = Соединение.NewObject("Запрос");
    ЗапросВнешний.Текст = 
        "ВЫБРАТЬ
        |	Продажи.Контрагент КАК Контрагент,
        |	Продажи.Номенклатура КАК Номенклатура,
        |	СУММА(Продажи.Сумма) КАК Сумма
        |ИЗ
        |	РегистрНакопления.Продажи КАК Продажи
        |СГРУППИРОВАТЬ ПО
        |	ИТОГИ СУММА(Сумма) ПО Контрагент, Номенклатура";
    
    РезультатЗапроса = ЗапросВнешний.Выполнить();
    
  3. Получаем выборку по группировкам:
    
    // Используем перечисление из объекта Соединение
    ВыборкаКонтрагент = РезультатЗапроса.Выбрать(Соединение.ОбходРезультатаЗапроса.ПоГруппировкам);
    
    Пока ВыборкаКонтрагент.Следующий() Цикл
        Сообщить("Контрагент: " + ВыборкаКонтрагент.Контрагент + ", Сумма: " + ВыборкаКонтрагент.Сумма);
        
        // Получаем вложенную выборку номенклатуры по группировке
        ВыборкаНоменклатура = ВыборкаКонтрагент.Выбрать(Соединение.ОбходРезультатаЗапроса.ПоГруппировкам);
        Пока ВыборкаНоменклатура.Следующий() Цикл
            Сообщить("  Номенклатура: " + ВыборкаНоменклатура.Номенклатура + ", Сумма: " + ВыборкаНоменклатура.Сумма);
        КонецЦикла;
    КонецЦикла;
    

Посмотрим на пример вариантов вызова различных режимов обхода выборки через внешний COM-объект:

  1. Прямой обход: Соединение.ОбходРезультатаЗапроса.Прямой
  2. Обход по группировкам: Соединение.ОбходРезультатаЗапроса.ПоГруппировкам
  3. Иерархический обход: Соединение.ОбходРезультатаЗапроса.ПоГруппировкамСИерархией

Ограничения производительности COM-соединений и альтернативные варианты

Выясним причину, почему построчный обход выборки через COM может существенным образом замедлять работу системы, и рассмотрим эффективные альтернативы.

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

Для оптимизации работы с внешними данными рекомендуется использовать следующие решения:

  1. Сериализация выгрузки через ЗначениеВСтрокуВнутр:

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

    
    // На стороне внешней базы через COM:
    ТаблицаВнешняя = РезультатЗапроса.Выгрузить();
    СтрокаДанных = Соединение.ЗначениеВСтрокуВнутр(ТаблицаВнешняя);
    
    // На стороне текущей базы:
    ТаблицаЛокальная = ЗначениеИзСтрокиВнутр(СтрокаДанных);
    

    Этот способ позволяет передать весь массив данных за один вызов и обходить иерархию или группировки уже локально с максимальной скоростью.

  2. Сериализация в JSON или XML:

    Формируем структуры или массивы на стороне внешнего соединения и сериализуем их в JSON-строку. В текущей базе декодируем строку обратно в объекты.

  3. Использование HTTP- или Web-сервисов:

    Вместо COM-соединения настраивается HTTP-сервис во внешней информационной базе, который возвращает сгруппированные данные в формате JSON. Это исключает зависимости от COM-компонентов и эффективно расходует лицензии.

  4. Перенос логики во внешнюю ИБ:

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

← На главную