При разработке обработок загрузки данных или интеграций между базами 1С в режиме управляемого приложения разработчики часто сталкиваются с ошибкой: «отсутствует отображение для типа ComОбъект». Ошибка возникает в момент вызова серверной процедуры или функции из клиентского контекста.
Разберем детально, почему платформа выдает такое исключение, как устроена передача типов между клиентом и сервером, а также рассмотрим правильные способы организации кода для чтения данных через COM-соединение и записи новых объектов базы данных.
В архитектуре клиент-серверной работы 1С Предприятия управляемые формы строго разделяют выполнение кода на директивы &НаКлиенте и &НаСервере. Вся передача параметров между клиентом и сервером выполняется через механизм XDTO-сериализации.
Объект типа COMОбъект (включая выборки, менеджеры и ссылки, полученные из внешнего соединения) не является сериализуемым типом платформы 1С. Платформа попросту не умеет трансформировать COM-указатель операционной системы Windows в сетевой пакет для передачи на серверную сторону. Попытка передать COM-объект или выборку из COM в качестве параметра процедуры с директивой &НаСервере неизбежно приводит к аварийному завершению с сообщением: «отсутствует отображение для типа ComОбъект».
Посмотрим на типичный ошибочный пример:
&НаКлиенте
Процедура Запустить(Команда)
Соединение = Новый COMОбъект("V83.Application");
Соединение.Connect("File=C:\Base;Usr=User;Pwd=123;");
Выборка = Соединение.Документы.РеализацияТоваровУслуг.Выбрать();
Пока Выборка.Следующий() Цикл
// ОШИБКА: Выборка является COM-объектом и не может быть передана на сервер
СоздатьДокументНаСервере(Выборка);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура СоздатьДокументНаСервере(ДокументCOM)
// Сервер падает еще до входа в тело процедуры
НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДок.Записать();
КонецПроцедуры
Наиболее простое и быстрое решение — выполнять подключение к внешней базе, выборку данных и запись новых объектов целиком в серверном контексте. В этом случае COM-объект создается прямо на сервере и не пересекает границу между клиентом и сервером.
Разберем по шагам реализацию единой процедуры на сервере:
&НаКлиенте, который просто вызывает серверную процедуру без параметров.COMОбъект.СоздатьДокумент()).Посмотрим на пример правильного серверного кода:
&НаКлиенте
Процедура ЗапуститьОбработку(Команда)
ВыполнитьЗагрузкуНаСервере();
КонецПроцедуры
&НаСервере
Процедура ВыполнитьЗагрузкуНаСервере()
Попытка
// Для оптимизации рекомендуется использовать V83.COMConnector вместо V83.Application
COMСоединитель = Новый COMОбъект("V83.COMConnector");
СтрокаПодключения = "File=""C:\1c-star-baza""; Usr=""Репнин Александр""; Pwd=""9985"";";
ВнешняяБаза = COMСоединитель.Connect(СтрокаПодключения);
Исключение
ВызватьИсключение "Не удалось подключиться к базе: " + ОписаниеОшибки();
КонецПопытки;
Выборка = ВнешняяБаза.Документы.РеализацияТоваровУслуг.Выбрать('20130101', '20140110');
Пока Выборка.Следующий() Цикл
НовРеал = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовРеал.Дата = ТекущаяДата();
// Получаем наименование контрагента в виде обычной строки
ИмяКонтрагента = Строка(Выборка.Контрагент.Наименование);
НайденныйКонтрагент = Справочники.Контрагенты.НайтиПоНаименованию(ИмяКонтрагента);
Если ЗначениеЗаполнено(НайденныйКонтрагент) Тогда
НовРеал.Контрагент = НайденныйКонтрагент;
КонецЕсли;
НовРеал.Организация = Справочники.Организации.НайтиПоНаименованию("Медресурс");
НовРеал.Записать();
КонецЦикла;
// Освобождаем память COM-объекта
ВнешняяБаза = Неопределено;
COMСоединитель = Неопределено;
КонецПроцедуры
Если сервер 1С работает под управлением 64-битной версии или ОС Linux (где COM-соединения могут быть недоступны), подключение создается на стороне клиента Windows. Чтобы передать информацию на сервер, данные из COM-объекта предварительно извлекаются в примитивные типы (Строка, Число, Дата, Булево) и помещаются в сериализуемую структуру или массив.
Рассмотрим пример правильной передачи данных через Массив и Структура:
&НаКлиенте
Процедура ЗапуститьНаКлиенте(Команда)
Соединитель = Новый COMОбъект("V83.COMConnector");
База = Соединитель.Connect("File=""C:\1c-star-baza""; Usr=""Admin""; Pwd=""123"";");
СписокДокументов = Новый Массив;
Выборка = База.Документы.РеализацияТоваровУслуг.Выбрать('20130101', '20140110');
Пока Выборка.Следующий() Цикл
ДанныеДокумента = Новый Структура;
ДанныеДокумента.Вставить("Дата", Выборка.Дата);
ДанныеДокумента.Вставить("КонтрагентНаименование", Строка(Выборка.Контрагент.Наименование));
ДанныеДокумента.Вставить("ОрганизацияНаименование", Строка(Выборка.Организация.Наименование));
СписокДокументов.Добавить(ДанныеДокумента);
КонецЦикла;
// Массив структур со строками и датами успешно сериализуется и передается на сервер
СоздатьДокументыПоСпискуНаСервере(СписокДокументов);
База = Неопределено;
Соединитель = Неопределено;
КонецПроцедуры
&НаСервере
Процедура СоздатьДокументыПоСпискуНаСервере(СписокДокументов)
Для Каждого СтрДанных Из СписокДокументов Цикл
НовРеал = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовРеал.Дата = СтрДанных.Дата;
НовРеал.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию(СтрДанных.КонтрагентНаименование);
НовРеал.Организация = Справочники.Организации.НайтиПоНаименованию(СтрДанных.ОрганизацияНаименование);
НовРеал.Записать();
КонецЦикла;
КонецПроцедуры
V83.COMConnector вместо V83.Application. Коннектор работает значительно быстрее и не запускает полный графический интерфейс толстого клиента.Неопределено, чтобы процесс внешней базы не зависал в оперативной памяти сервера или клиента.comcntr.dll разрядности x64.