При настройке интеграции между различными конфигурациями «1С:Предприятие» разработчики часто сталкиваются с необходимостью организовать прямое подключение к базе-источнику для выборки и загрузки данных. Типичный сценарий — подключение из современной базы на управляемом приложении (например, 1С:ERP, 1С:Комплексная автоматизация или 1С:Управление торговлей) к устаревшей базе на обычных формах, такой как «1С:Управление производственным предприятием» (УПП) редакции 1.3.
Обе базы могут работать под управлением СУБД MS SQL Server. В процессе реализации такого подключения через механизм COMConnector часто возникает критическая ошибка передачи данных между клиентом и сервером. В этой статье мы подробно разберем причину возникновения данной проблемы и рассмотрим надежные способы ее устранения.
Проанализируем ситуацию, с которой сталкивается разработчик. При попытке инициализировать COM-соединение в коде управляемой формы вызывается функция, определяющая версию платформы и возвращающая созданный COM-объект. На этом этапе система выдает ошибку следующего вида:
Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа.
по причине:
Ошибка преобразования данных XDTO:
Запись значения свойства 'ret':
форма: Элемент
имя: {http://v8.1c.ru/8.2/managed-application/modules}ret по причине:
Ошибка отображения типов:
Отсутствует отображение для типа 'COMОбъект'
Давайте разберем, почему это происходит. В управляемом приложении 1С действует жесткое разделение контекстов выполнения кода на клиентский (&НаКлиенте) и серверный (&НаСервере).
Когда мы вызываем экспортную функцию получения COM-объекта, выполняющуюся на сервере (или в серверном общем модуле), и пытаемся вернуть результат ее работы обратно на клиент, платформа инициирует процесс сериализации данных. Передача любых данных между сервером «1С» и клиентским местом (будь то тонкий клиент или веб-клиент) осуществляется через XML-подобный формат XDTO.
Главное правило архитектуры 1С: Объект типа COMОбъект (как и Запрос, ВыборкаИзРезультатаЗапроса, ГрафическаяСхема и некоторые другие внутренние типы платформы) не является сериализуемым. Платформа физически не может преобразовать COM-соединение в XML-пакет для передачи по сети. Именно поэтому возникает ошибка отображения типов XDTO.
Для того чтобы избежать ошибок сериализации, мы должны организовать работу так, чтобы весь жизненный цикл COM-соединения — от создания объекта до выборки данных и закрытия подключения — проходил строго внутри одного серверного вызова. На клиент мы должны возвращать только простые, сериализуемые типы данных: структуры, массивы, соответствия или таблицы значений (которые платформа умеет передавать между клиентом и сервером).
Рассмотрим по шагам, как переписать логику подключения и выборки документа «Поступление товаров и услуг» из базы УПП 1.3.
Вместо того чтобы возвращать сам COM-объект, мы создадим на сервере процедуру, которая подключается к источнику, находит нужный документ, собирает его реквизиты в структуру и передает эту структуру на клиент.
Посмотрим на пример реализации серверной функции:
&НаСервере
Функция ПолучитьДанныеДокументаИзУПП(НомерДокумента, ДатаДокумента)
// 1. Формируем строку подключения к SQL-базе источника
СтрокаПодключения = "srvr='ИмяСервераБД'; ref='ИмяБазыУПП'; usr='Логин'; pwd='Пароль';";
// 2. Инициализируем COM-соединение локально на сервере
ИмяComОбъекта = "V83.COMConnector"; // Или V82.COMConnector в зависимости от платформы источника
Попытка
COMConnector = Новый COMОбъект(ИмяComОбъекта);
СоединениеИсточника = COMConnector.Connect(СтрокаПодключения);
Исключение
ВызватьИсключение "Не удалось установить подключение к УПП: " + ОписаниеОшибки();
КонецПопытки;
// 3. Создаем структуру для возврата данных
ДанныеДокумента = Новый Структура;
ДанныеДокумента.Вставить("ДокументНайден", Ложь);
ДанныеДокумента.Вставить("Реквизиты", Новый Структура);
ДанныеДокумента.Вставить("ТабличнаяЧастьТовары", Новый Массив);
// 4. Ищем документ в базе источника средствами COM
// Используем менеджер запросов внешней базы для быстрого поиска
ЗапросИсточника = СоединениеИсточника.NewObject("Запрос");
ЗапросИсточника.Текст =
"ВЫБРАТЬ
| Ссылка,
| Контрагент.Наименование КАК КонтрагентНаименование,
| ДоговорКонтрагента.Наименование КАК ДоговорНаименование,
| Организация.Наименование КАК ОрганизацияНаименование
|ИЗ
| Документ.ПоступлениеТоваровУслуг КАК Поступление
|ГДЕ
| Поступление.Номер = &Номер
| И Поступление.Дата = &Дата";
ЗапросИсточника.УстановитьПараметр("Номер", НомерДокумента);
ЗапросИсточника.УстановитьПараметр("Дата", ДатаДокумента);
РезультатЗапроса = ЗапросИсточника.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
ДанныеДокумента.ДокументНайден = Истина;
// Заполняем структуру реквизитов (передаем только простые типы: строки, числа, даты)
СтруктураРеквизитов = ДанныеДокумента.Реквизиты;
СтруктураРеквизитов.Вставить("КонтрагентНаименование", Выборка.КонтрагентНаименование);
СтруктураРеквизитов.Вставить("ДоговорНаименование", Выборка.ДоговорНаименование);
СтруктураРеквизитов.Вставить("ОрганизацияНаименование", Выборка.ОрганизацияНаименование);
// Получаем табличную часть "Товары" через COM-объект ссылки
СсылкаНаДокумент = Выборка.Ссылка;
Для Каждого СтрокаТовары Из СсылкаНаДокумент.Товары Цикл
СтрокаТЧ = Новый Структура;
СтрокаТЧ.Вставить("НоменклатураНаименование", СтрокаТовары.Номенклатура.Наименование);
СтрокаТЧ.Вставить("Количество", СтрокаТовары.Количество);
СтрокаТЧ.Вставить("Цена", СтрокаТовары.Цена);
СтрокаТЧ.Вставить("Сумма", СтрокаТовары.Сумма);
ДанныеДокумента.ТабличнаяЧастьТовары.Добавить(СтрокаТЧ);
КонецЦикла;
КонецЕсли;
// Освобождаем COM-объекты явным образом
СоединениеИсточника = Неопределено;
COMConnector = Неопределено;
Возврат ДанныеДокумента;
КонецФункции
При таком подходе на клиент возвращается обычная сериализуемая структура ДанныеДокумента, содержащая массивы простых структур. Это полностью исключает возникновение ошибок XDTO-конвертации и обеспечивает быструю передачу данных по сети.
Если архитектура вашего решения предполагает интерактивный выбор документов пользователем непосредственно из формы (например, динамическое открытие списков внешней базы прямо в интерфейсе приемника), мы можем инициализировать COM-объект непосредственно в контексте &НаКлиенте.
Для реализации этого метода необходимо соблюдение нескольких условий:
comcntr.dll соответствующей версии платформы «1С».Проанализируем пример клиентского подключения:
&НаКлиенте
Процедура ПодключитьсяКИсточникуНаКлиенте()
СтрокаПодключения = "srvr='ИмяСервераБД'; ref='ИмяБазыУПП'; usr='Логин'; pwd='Пароль';";
Попытка
// Создаем объект непосредственно в памяти клиентского процесса
COMConnector = Новый COMОбъект("V83.COMConnector");
COMConnection = COMConnector.Connect(СтрокаПодключения);
ПоказатьПредупреждение(, "Успешно подключено на клиенте!");
Исключение
ПоказатьПредупреждение(, "Ошибка подключения на клиенте: " + ОписаниеОшибки());
КонецПопытки;
// Здесь мы можем использовать COMConnection для интерактивной работы в рамках этой процедуры
КонецПроцедуры
Важное ограничение: Данный способ категорически не подходит, если пользователи работают с базой-приемником через веб-клиент (браузер) или если рабочие места пользователей развернуты на операционных системах Linux/macOS, так как технология COM является проприетарной для Microsoft Windows.
В ходе обсуждений на форумах часто звучат предложения отказаться от COM-соединения в пользу прямого чтения таблиц базы данных SQL Server через механизм ADO (ActiveX Data Objects). Давайте выясним, почему для бизнес-задач (таких как загрузка документов 1С) это является крайне неэффективным решением:
_Document150 или _Reference85). Эти имена могут меняться при обновлении конфигурации или изменении метаданных.JOIN, что усложняет код в сотни раз.Использование COMConnector позволяет абстрагироваться от низкоуровневой структуры SQL-таблиц и работать с привычными объектами метаданных 1С на стандартном встроенном языке.
Даже при правильном распределении контекстов выполнения кода (Решение №1), на стороне сервера приложений вы можете столкнуться с системными ошибками инициализации COM-объектов. Рассмотрим основные проблемы и способы их решения:
Если сервер «1С:Предприятия» базы-приемника является 64-разрядным (64-bit), то для выполнения кода на сервере должна быть зарегистрирована 64-битная версия библиотеки comcntr.dll. Если вы получаете ошибку «Класс не зарегистрирован», выполните регистрацию библиотеки вручную через командную строку от имени администратора:
regsvr32 "C:\Program Files\1cv8\[ВерсияПлатформы]\bin\comcntr.dll"
В некоторых случаях (особенно при работе под управлением Windows Server) учетная запись, от имени которой запущен сервер приложений «1С» (обычно это usr1cv8), не имеет достаточных прав для создания DCOM-объектов. Решением является создание выделенного приложения COM+ в «Службах компонентов» Windows, куда добавляется библиотека comcntr.dll, и настройка запуска этого приложения от имени администратора системы.
Помните, что каждое активное COM-соединение к внешней базе 1С расходует одну дополнительную сеансовую лицензию платформы. Убедитесь, что на сервере лицензирования имеется достаточный пул свободных лицензий для выполнения интеграционных процедур.
Если обе базы данных находятся в активной разработке, мы рекомендуем рассмотреть более современную и кроссплатформенную альтернативу COM-соединениям — использование HTTP-сервисов.
Вы можете опубликовать в базе УПП 1.3 простейший HTTP-сервис, который будет принимать запросы с параметрами (номер и дата документа) и возвращать структурированные данные в формате JSON. База-приемник сможет отправлять стандартные HTTP-запросы с помощью встроенного класса платформы HTTPСоединение.
Этот подход обладает неоспоримыми преимуществами: