При работе в среде 1С:Предприятие 8.3 (особенно в конфигурациях на управляемых формах, таких как УТ 11.5) программисты часто сталкиваются с необходимостью получения данных из внешних баз через COMОбъект. Типичная сложность возникает, когда соединение создано на клиенте (например, для интерактивного выбора файла базы или отображения индикатора прогресса), а данные нужно обработать на сервере. Попытка передать COMОбъект напрямую в серверную процедуру приводит к ошибке: «Ошибка отображения типов: Отсутствует отображение для типа 'COMОбъект'». Рассмотрим, почему это происходит и как правильно организовать передачу таблицы значений.
Разберем ситуацию: COMОбъект (в нашем случае V83.COMConnector) является указателем на область памяти в конкретном процессе операционной системы. Если вы создали соединение на стороне тонкого клиента, этот объект существует только в адресном пространстве клиентского приложения. Сервер 1С — это отдельный процесс, зачастую работающий на другом физическом компьютере. Платформа не может автоматически «перебросить» живое соединение между процессами, поэтому передача самого объекта в параметры серверного метода невозможна.
Второй важный момент: объект ТаблицаЗначений не существует на тонком клиенте. На клиенте мы работаем с объектом ДанныеФормыКоллекция. Это накладывает дополнительные ограничения на способы обработки полученных данных.
Проанализируем метод, предложенный в обсуждении, который позволяет обойти ограничение передачи типов. Идея заключается в том, чтобы заставить саму внешнюю базу (через COM-соединение) превратить таблицу значений в строку, передать эту строку на сервер текущей базы, и там превратить её обратно в объект.
Рассмотрим пример реализации на стороне клиента:
&НаКлиенте
Процедура ВыполнитьПереносДанных()
// Предположим, СоединениеБД уже установлено на клиенте
ТЗвнутр = СоединениеБД.ВыполнитьЗапросИПолучитьТЗ();
Если ТЗвнутр <> Неопределено Тогда
// Используем метод внешнего соединения для сериализации
СтрСериализации = СоединениеБД.ValueToStringInternal(ТЗвнутр);
// Передаем строку на сервер
ОбработатьТЗНаСервере(СтрСериализации);
КонецЕсли;
КонецПроцедуры
Теперь разберем, что происходит на сервере. Нам нужно восстановить таблицу из строки. Важно понимать, что метод ЗначениеИзСтрокиВнутр должен вызываться именно на сервере, так как на клиенте объект ТаблицаЗначений недопустим.
&НаСервере
Процедура ОбработатьТЗНаСервере(Знач СтрСериализации)
// Восстанавливаем таблицу значений из системной строки
ТЗ = ЗначениеИзСтрокиВнутр(СтрСериализации);
// Теперь ТЗ - это полноценная таблица значений текущей базы
Для Каждого СтрокаТЗ Из ТЗ Цикл
// Обработка данных
КонецЦикла;
КонецПроцедуры
Важное предостережение: Метод ValueToStringInternal сохраняет внутренние идентификаторы (GUID) типов данных. Если структура колонок таблицы в базе-источнике (например, УТ 10.3) содержит ссылки на объекты, которых нет в текущей базе, при десериализации вы можете получить «Битые ссылки». Этот метод лучше всего подходит для передачи примитивных типов: строк, чисел, дат и булево.
Если ваша основная задача — выводить индикатор прогресса на клиенте, выясним, стоит ли вообще передавать всю таблицу. Чаще всего для визуализации достаточно знать общее количество строк и номер текущей строки. Выясним, как это реализовать эффективнее:
Посмотрим на пример кода, который позволяет избежать «зависания» интерфейса без передачи тяжелых COM-объектов:
&НаКлиенте
Процедура ЗагрузкаСИндикатором()
ВсегоЗаписей = СоединениеБД.ПолучитьКоличествоЗаписей();
Элементы.Индикатор.МаксимальноеЗначение = ВсегоЗаписей;
Для НомерСтроки = 1 По ВсегоЗаписей Цикл
ДанныеСтрокиСтрокой = СоединениеБД.ПолучитьСтрокуДанныхВФорматеJSON(НомерСтроки);
ОбработатьСтрокуНаСервере(ДанныеСтрокиСтрокой);
Индикатор = НомерСтроки; // Обновление на форме
ОбработкаПрерыванияПользователя();
КонецЦикла;
КонецПроцедуры
Проанализируем более современный подход. Вместо использования «внутренних строк», которые считаются устаревшими (Legacy), рекомендуется использовать XML-сериализацию. Это гарантирует, что данные будут переданы корректно даже между разными версиями платформ.
Выполним следующие шаги:
ЧтениеXML и СериализаторXDTO.Этот способ позволяет избежать ошибок типизации COMОбъект, так как строка XML — это универсальный транспортный формат.
Рассмотрим ситуацию, когда таблицу нужно не просто обработать, но и показать пользователю на форме. Помните, что процедура &НаСервере не может просто вернуть ТаблицуЗначений на клиент. Вы должны скопировать данные в реквизит формы. Воспользуемся методом ЗначениеВДанныеФормы:
&НаСервере
Процедура ЗагрузитьТЗВРеквизит(СтрСериализации)
ТЗ = ЗначениеИзСтрокиВнутр(СтрСериализации);
// РеквизитФормыТЗ - это имя вашей таблицы на форме
ЗначениеВДанныеФормы(ТЗ, Объект.РеквизитФормыТЗ);
КонецПроцедуры
Подведем итог: работа с COM-объектами на клиенте требует строгого разделения контекстов. Никогда не пытайтесь передать сам COM-объект на сервер. Используйте промежуточную сериализацию в строку (XML, JSON или ValueToStringInternal) для «переезда» данных через границу «Клиент — Сервер».