Интеграция нескольких баз данных «1С:Предприятие» — одна из самых частых задач, с которыми сталкиваются разработчики. Использование технологии COM-соединения (Component Object Model) позволяет напрямую подключаться к внешней базе данных, считывать информацию, а также создавать новые объекты программным путем. Однако этот процесс таит в себе множество подводных камней: от несовместимости типов данных до зависания сеансов и трудностей с отладкой кода.
В этой статье мы подробно разберем, как правильно организовать процесс создания, заполнения и записи документов во внешней базе через COM-соединение, проанализируем частые ошибки разработчиков и рассмотрим лучшие практики программирования.
Для начала работы нам необходимо корректно инициализировать COM-объект и установить соединение с базой-приемником. Платформа 1С предоставляет для этого специальный класс COMConnector. Важно динамически определять версию платформы, чтобы избежать ошибок инициализации при обновлении системы.
Рассмотрим пример кода, который решает эту задачу:
Функция ПолучитьCOMОбъектПоВерсииПлатформы() Экспорт
ИмяComОбъекта = "";
Инфо = Новый СистемнаяИнформация;
Если Найти(Инфо.ВерсияПриложения, "8.3") > 0 Тогда
ИмяComОбъекта = "V83.COMConnector";
ИначеЕсли Найти(Инфо.ВерсияПриложения, "8.2") > 0 Тогда
ИмяComОбъекта = "V82.COMConnector";
Иначе
ВызватьИсключение "Не удалось определить версию платформы для создания COM-соединения";
КонецЕсли;
Попытка
Возврат Новый COMОбъект(ИмяComОбъекта);
Исключение
ЗаписьЖурналаРегистрации("Интеграция.COM", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка инициализации COM-объекта: " + ОписаниеОшибки());
ВызватьИсключение "Не удалось инициализировать COM-объект " + ИмяComОбъекта;
КонецПопытки;
КонецФункции
После получения коннектора мы выполняем подключение к базе. Строка подключения зависит от типа базы данных (файловая или клиент-серверная). Обратите внимание на обработку исключений — это обязательное условие стабильной работы интеграции:
СтрокаПодключения = "file='\\Server\1C_Bases\Accounting\'; usr='Администратор'; pwd='Пароль';";
COMConnector = ПолучитьCOMОбъектПоВерсииПлатформы();
Попытка
ComConnection = COMConnector.Connect(СтрокаПодключения);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Ошибка подключения к базе-приемнику: " + ОписаниеОшибки();
Сообщение.Сообщить();
Возврат;
КонецПопытки;
Когда соединение успешно установлено, мы получаем доступ к метаданным внешней базы через переменную ComConnection. Создание нового документа происходит через менеджер соответствующего класса объектов.
Рассмотрим пример создания документа «Реализация товаров и услуг»:
МенеджерДокумента = ComConnection.Документы.РеализацияТоваровУслуг;
НовыйДокумент = МенеджерДокумента.СоздатьДокумент();
// Заполняем базовые реквизиты
НовыйДокумент.Дата = ТекущаяДата();
// Платформа автоматически сгенерирует номер при записи, но мы можем задать префикс или номер вручную:
НовыйДокумент.УстановитьНовыйНомер("РТ");
Одна из главных логических ошибок начинающих разработчиков — попытка присвоить реквизитам COM-объекта значения ссылочных типов из текущей (локальной) базы. Например, следующая конструкция приведет к ошибке «Несоответствие типов»:
// ОШИБКА! Строка.Номенклатура — это ссылка текущей базы. Внешняя база её не поймет.
НоваяСтрокаТабЧасти.Номенклатура = Строка.Номенклатура;
Дело в том, что COM-база работает в собственном адресном пространстве памяти. Ей ничего неизвестно о внутренних идентификаторах (GUID) локальной базы, даже если конфигурации абсолютно идентичны. Чтобы передать ссылку, нам необходимо найти аналогичный объект в контексте внешней базы.
Способ 1. Поиск по реквизиту (код, наименование, артикул)
Этот способ прост, но менее надежен, так как коды или наименования могут дублироваться или изменяться пользователями:
КодНоменклатуры = Строка.Номенклатура.Код;
СсылкаВнешняя = ComConnection.Справочники.Номенклатура.НайтиПоКоду(КодНоменклатуры);
Если Не СсылкаВнешняя.Пустая() Тогда
НоваяСтрокаТабЧасти.Номенклатура = СсылкаВнешняя;
КонецЕсли;
Способ 2. Синхронизация по Уникальному Идентификатору (GUID) — Рекомендуемый метод
Этот метод гарантирует стопроцентное совпадение объектов, поскольку уникальный идентификатор GUID неизменен. Мы получаем строковое представление GUID из локальной базы, инициализируем объект УникальныйИдентификатор внутри COM-соединения и находим ссылку:
ЛокальныйGUID = Строка(Строка.Номенклатура.УникальныйИдентификатор());
// Создаем объект GUID в контексте внешней базы
ВнешнийGUID = ComConnection.NewObject("УникальныйИдентификатор", ЛокальныйGUID);
// Получаем ссылку во внешней базе
СсылкаВнешняя = ComConnection.Справочники.Номенклатура.ПолучитьСсылка(ВнешнийGUID);
// Проверяем, существует ли этот объект во внешней базе
Если СсылкаВнешняя.ПолучитьОбъект() = Неопределено Тогда
// Объект не найден. Здесь можно прописать логику его создания или выгрузки
Иначе
НоваяСтрокаТабЧасти.Номенклатура = СсылкаВнешняя;
КонецЕсли;
Аналогично ссылкам справочников, системные перечисления платформы и перечисления самой конфигурации нельзя передавать напрямую. Обращаться к ним нужно строго через объект подключения ComConnection.
Пример работы с системным перечислением (Режим записи документа):
// НЕПРАВИЛЬНО: Использовать локальное перечисление РежимЗаписиДокумента
// ПРАВИЛЬНО: Обратиться через COM-соединение
РежимПроведения = ComConnection.РежимЗаписиДокумента.Проведение;
НовыйДокумент.Записать(РежимПроведения);
Пример работы с прикладным перечислением конфигурации (например, «Вид операции»):
НовыйДокумент.ВидОперации = ComConnection.Перечисления.ВидыОперацийРеализацииТоваров.ПродажаКомиссия;
По умолчанию при записи документа во внешней базе запускаются все прикладные подписки на события и обработчики (ПередЗаписью, ПриЗаписи, ОбработкаПроведения). Если во внешней базе настроен строгий контроль остатков, проверка заполнения специфических реквизитов или ограничение прав, документ может не записаться.
Чтобы записать документ в «сыром» виде, минуя прикладные проверки конфигурации, используем свойство ОбменДанными.Загрузка. Установим его значение в Истина:
// Обратите внимание на правильный синтаксис обращения к свойству
НовыйДокумент.ОбменДанными.Загрузка = Истина;
// Теперь документ запишется без вызова лишних транзакционных проверок
НовыйДокумент.Записать(ComConnection.РежимЗаписиДокумента.Запись);
Важно: Если вам требуется именно провести документ с формированием движений по регистрам, то отключать проверки с помощью режима загрузки не рекомендуется, иначе вы рискуете получить некорректные или пустые регистры учета.
Часто возникает ситуация: код выполняется без видимых ошибок, но документ не проводится или заполняется некорректно из-за скрытых отказов внутри процедур внешней базы. В таком случае нам необходима сквозная отладка.
Для того чтобы иметь возможность заходить отладчиком в код базы-приемника при вызовах через COM-соединение, выполним следующие шаги:
-debug).При создании документов и заполнении их табличных частей (например, товаров, услуг, акцизов) сбой может произойти на любом этапе. Чтобы база данных не оставалась в промежуточном («битом») состоянии, весь процесс создания документов необходимо оборачивать в транзакцию на стороне внешней базы:
ComConnection.НачатьТранзакцию();
Попытка
Менеджер = ComConnection.Документы.РеализацияТоваровУслуг;
ДокОбъект = Менеджер.СоздатьДокумент();
// Заполнение шапки и табличной части...
ДокОбъект.Записать(ComConnection.РежимЗаписиДокумента.Проведение);
// Если все операции прошли успешно, фиксируем изменения в базе данных
ComConnection.ЗафиксироватьТранзакцию();
Исключение
// В случае любой непредвиденной ошибки откатываем все изменения назад
ComConnection.ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Интеграция.COM", УровеньЖурналаРегистрации.Ошибка, , ,
"Транзакция отменена. Ошибка: " + ОписаниеОшибки());
КонецПопытки;
Каждое открытое COM-соединение потребляет оперативную память сервера приложений 1С и занимает одну полноценную клиентскую лицензию. Если не уничтожать объекты принудительно, сеансы будут оставаться активными ("зависать"), что со временем приведет к нехватке лицензий и перегрузке сервера.
В конце выполнения процедуры интеграции всегда явно очищайте ссылки на COM-объекты:
// Освобождаем память сервера и закрываем сеанс в базе-приемнике
ComConnection = Неопределено;
COMConnector = Неопределено;
Хотя технология COM остается популярной и простой в реализации для внутренних обменов Windows-инфраструктуры, современные стандарты разработки в среде 1С рекомендуют уходить от этого подхода по следующим причинам:
Вместо COM-соединений для современных интеграционных задач рекомендуется разрабатывать **HTTP-сервисы (REST API)** внутри базы-приемника. В таком сценарии база-источник просто отправляет легкий структурированный JSON-пакет данных, а база-приемник на своей стороне самостоятельно и безопасно обрабатывает запрос, проверяет заполнение полей и создает документ стандартными средствами платформы.