Как передать таблицу значений из COM-соединения на сервер в управляемых формах?

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

При работе в среде 1С:Предприятие 8.3 (особенно в конфигурациях на управляемых формах, таких как УТ 11.5) программисты часто сталкиваются с необходимостью получения данных из внешних баз через COMОбъект. Типичная сложность возникает, когда соединение создано на клиенте (например, для интерактивного выбора файла базы или отображения индикатора прогресса), а данные нужно обработать на сервере. Попытка передать COMОбъект напрямую в серверную процедуру приводит к ошибке: «Ошибка отображения типов: Отсутствует отображение для типа 'COMОбъект'». Рассмотрим, почему это происходит и как правильно организовать передачу таблицы значений.

Анализ причины ошибки

Разберем ситуацию: COMОбъект (в нашем случае V83.COMConnector) является указателем на область памяти в конкретном процессе операционной системы. Если вы создали соединение на стороне тонкого клиента, этот объект существует только в адресном пространстве клиентского приложения. Сервер 1С — это отдельный процесс, зачастую работающий на другом физическом компьютере. Платформа не может автоматически «перебросить» живое соединение между процессами, поэтому передача самого объекта в параметры серверного метода невозможна.

Второй важный момент: объект ТаблицаЗначений не существует на тонком клиенте. На клиенте мы работаем с объектом ДанныеФормыКоллекция. Это накладывает дополнительные ограничения на способы обработки полученных данных.

Решение 1: Сериализация через внутреннюю строку

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

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


&НаКлиенте
Процедура ВыполнитьПереносДанных()
    // Предположим, СоединениеБД уже установлено на клиенте
    ТЗвнутр = СоединениеБД.ВыполнитьЗапросИПолучитьТЗ(); 
    
    Если ТЗвнутр <> Неопределено Тогда
        // Используем метод внешнего соединения для сериализации
        СтрСериализации = СоединениеБД.ValueToStringInternal(ТЗвнутр);
        
        // Передаем строку на сервер
        ОбработатьТЗНаСервере(СтрСериализации);
    КонецЕсли;
КонецПроцедуры

Теперь разберем, что происходит на сервере. Нам нужно восстановить таблицу из строки. Важно понимать, что метод ЗначениеИзСтрокиВнутр должен вызываться именно на сервере, так как на клиенте объект ТаблицаЗначений недопустим.


&НаСервере
Процедура ОбработатьТЗНаСервере(Знач СтрСериализации)
    // Восстанавливаем таблицу значений из системной строки
    ТЗ = ЗначениеИзСтрокиВнутр(СтрСериализации);
    
    // Теперь ТЗ - это полноценная таблица значений текущей базы
    Для Каждого СтрокаТЗ Из ТЗ Цикл
        // Обработка данных
    КонецЦикла;
КонецПроцедуры

Важное предостережение: Метод ValueToStringInternal сохраняет внутренние идентификаторы (GUID) типов данных. Если структура колонок таблицы в базе-источнике (например, УТ 10.3) содержит ссылки на объекты, которых нет в текущей базе, при десериализации вы можете получить «Битые ссылки». Этот метод лучше всего подходит для передачи примитивных типов: строк, чисел, дат и булево.

Решение 2: Использование структуры или массива для индикации

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

  1. Выполните расчет общего количества данных на сервере или через COM один раз.
  2. Организуйте цикл обработки порциями.
  3. На каждом шаге цикла обновляйте переменную на клиенте, связанную с реквизитом формы (индикатором).

Посмотрим на пример кода, который позволяет избежать «зависания» интерфейса без передачи тяжелых COM-объектов:


&НаКлиенте
Процедура ЗагрузкаСИндикатором()
    ВсегоЗаписей = СоединениеБД.ПолучитьКоличествоЗаписей();
    Элементы.Индикатор.МаксимальноеЗначение = ВсегоЗаписей;
    
    Для НомерСтроки = 1 По ВсегоЗаписей Цикл
        ДанныеСтрокиСтрокой = СоединениеБД.ПолучитьСтрокуДанныхВФорматеJSON(НомерСтроки);
        ОбработатьСтрокуНаСервере(ДанныеСтрокиСтрокой);
        
        Индикатор = НомерСтроки; // Обновление на форме
        ОбработкаПрерыванияПользователя();
    КонецЦикла;
КонецПроцедуры

Решение 3: Сериализация через XML/XDTO (наиболее надежный метод)

Проанализируем более современный подход. Вместо использования «внутренних строк», которые считаются устаревшими (Legacy), рекомендуется использовать XML-сериализацию. Это гарантирует, что данные будут переданы корректно даже между разными версиями платформ.

Выполним следующие шаги:

  1. На стороне внешней базы (в COM) выгружаем ТЗ в массив структур.
  2. Преобразуем массив в XML-строку.
  3. Передаем XML-строку на сервер текущей базы.
  4. Разбираем XML с помощью ЧтениеXML и СериализаторXDTO.

Этот способ позволяет избежать ошибок типизации COMОбъект, так как строка XML — это универсальный транспортный формат.

Рекомендации по работе с данными формы

Рассмотрим ситуацию, когда таблицу нужно не просто обработать, но и показать пользователю на форме. Помните, что процедура &НаСервере не может просто вернуть ТаблицуЗначений на клиент. Вы должны скопировать данные в реквизит формы. Воспользуемся методом ЗначениеВДанныеФормы:


&НаСервере
Процедура ЗагрузитьТЗВРеквизит(СтрСериализации)
    ТЗ = ЗначениеИзСтрокиВнутр(СтрСериализации);
    // РеквизитФормыТЗ - это имя вашей таблицы на форме
    ЗначениеВДанныеФормы(ТЗ, Объект.РеквизитФормыТЗ);
КонецПроцедуры

Подведем итог: работа с COM-объектами на клиенте требует строгого разделения контекстов. Никогда не пытайтесь передать сам COM-объект на сервер. Используйте промежуточную сериализацию в строку (XML, JSON или ValueToStringInternal) для «переезда» данных через границу «Клиент — Сервер».

← На главную