При организации интеграции между двумя базами 1С через механизм COM-соединения разработчики нередко сталкиваются с ситуацией, когда код запроса выдает ошибку «Метод объекта не обнаружен» или в отладчике методы Выполнить(), Execute(), Пустой() и Следующий() вызывают исключения. Рассмотрим подробно причины такого поведения платформы, разберем настройку внешнего соединения и напишем надежный код выборки данных.
Когда мы пытаемся вычислить вызовы методов удаленного объекта (такие как _Запрос.Выполнить() или РезультатВыборки.Следующий()) непосредственно в окне «Табло» или «Вычислить выражение», среда разработки 1С часто возвращает сообщение об ошибке вида «Метод объекта не обнаружен» или Неопределено.
Важно понимать: это связано с особенностями маршалинга через интерфейс IDispatch в режиме отладки. Во время фактического исполнения модуля на клиенте или сервере эти методы отрабатывают штатно. Попытка вызывать методы с изменением состояния выборки через табло отладчика приводит к нарушению внутреннего указателя курсора или ложным диагностическим сообщениям.
Если само COM-соединение не инициализирует объекты должным образом, а методы COM-объектов ведут себя нестабильно, необходимо убедиться в корректности регистрации внешней библиотеки платформы comcntr.dll нужной версии и разрядности. Проанализируем шаги перерегистрации компоненты:
cmd.exe от имени Администратора.
regsvr32 "C:\Program Files (x86)\1cv8\8.3.9.2170\bin\comcntr.dll"
Для 64-разрядного сервера 1С аналогично регистрируется библиотека из каталога Program Files\1cv8\.... Успешная регистрация гарантирует корректную работу фабрики классов OLE/COM.
Типичная ошибка при написании цикла обработки данных заключается в попытке прочитать поля выборки через сам объект РезультатЗапроса, а не через ВыборкаИзРезультатаЗапроса. Объект РезультатЗапроса не содержит в себе именованных полей выборки — обращаться к ним необходимо исключительно через переменную выборки после вызова метода Следующий().
Вторая распространенная ошибка — установка параметров запроса. Если в запросе выполняется соединение с виртуальной таблицей, передавать ссылки из внешней базы нужно корректно, а условия фильтрации накладывать в параметрах самой виртуальной таблицы, а не в блоке ГДЕ, чтобы не перегружать удаленную базу избыточными вычислениями итогов.
Разберем рабочий пример, объединяющий правильное подключение к информационной базе, установку параметров и корректный обход выборки.
Сначала подготовим функцию подключения к удаленной базе данных:
Функция ПолучитьПодключениеКОсновнойБД(ПутьКБазе, Пользователь, Пароль)
Если СокрЛП(Пароль) = "" Тогда
ПараметрыСоединения = "File=""" + ПутьКБазе + """; Usr=""" + Пользователь + """;";
Иначе
ПараметрыСоединения = "File=""" + ПутьКБазе + """; Usr=""" + Пользователь + """; Pwd=""" + Пароль + """;";
КонецЕсли;
Попытка
V83COMConnector = Новый COMОбъект("V83.COMConnector");
Возврат V83COMConnector.Connect(ПараметрыСоединения);
Исключение
Сообщить("Ошибка подключения к внешней базе данных!");
Сообщить(ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Теперь рассмотрим корректный алгоритм выполнения запроса к регистру накопления ТоварыНаСкладах в подключенной базе:
Соединение = ПолучитьПодключениеКОсновнойБД(Объект.ПутьКБазеДанных, Объект.ИмяПользователя, Объект.Пароль);
Если Соединение = Неопределено Тогда
Возврат;
КонецЕсли;
Попытка
// Создаем удаленный объект Запрос
_Запрос = Соединение.NewObject("Query");
// Оптимальный текст запроса с отбором в параметрах виртуальной таблицы
_Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Склад КАК Склад,
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.Характеристика КАК Характеристика,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток,
| ТоварыНаСкладахОстатки.ор_РезервОстаток КАК РезервОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад И Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОстатки";
// Находим ссылки в удаленной базе по кодам
НоменклатураСсылка = Соединение.Справочники.Номенклатура.НайтиПоКоду(СокрЛП(Объект.Номенклатура.Код));
СкладСсылка = Соединение.Справочники.Склады.НайтиПоКоду(СокрЛП(Объект.Склад.Код));
_Запрос.УстановитьПараметр("Склад", СкладСсылка);
_Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылка);
// Выполняем запрос и получаем выборку
РезультатЗапроса = _Запрос.Выполнить();
РезультатВыборки = РезультатЗапроса.Выбрать();
Пока РезультатВыборки.Следующий() Цикл
// Обращение к полям выполняется строго через объект выборки:
ОстатокНаСкладе = РезультатВыборки.КоличествоОстаток;
Резерв = РезультатВыборки.РезервОстаток;
Если ОстатокНаСкладе >= Объект.Количество Тогда
Сообщить("Товар есть на складе в количестве: " + Строка(ОстатокНаСкладе));
Если Резерв > 0 Тогда
Сообщить("Количество резерва: " + Строка(Резерв));
КонецЕсли;
Иначе
Сообщить("Недостаточно остатка на складе магазина.");
КонецЕсли;
КонецЦикла;
Исключение
Сообщить("Ошибка при обработке запроса через COM: " + ОписаниеОшибки());
КонецПопытки;
// Очищаем COM-ссылки для освобождения ресурсов сеанса
РезультатВыборки = Неопределено;
РезультатЗапроса = Неопределено;
_Запрос = Неопределено;
Соединение = Неопределено;
В распределенных операциях метод РезультатЗапроса.Выгрузить() нередко оказывается удобнее прямого обхода выборки, так как возвращает объект ТаблицаЗначений. Если выборка через удаленный курсор работает медленно из-за сетевых накладных расходов при каждом вызове Следующий(), выгрузка таблицы сразу передает результат в один шаг:
РезультатЗапроса = _Запрос.Выполнить();
ТаблицаРезультата = РезультатЗапроса.Выгрузить();
Для Каждого Стр Из ТаблицаРезультата Цикл
Остаток = Стр.КоличествоОстаток;
// Дальнейшая обработка строк таблицы
КонецЦикла;
Рекомендация: если к удаленной базе выполняется много запросов, предпочтительно выносить логику в экспортную функцию общего модуля удаленной базы (с флагом «Внешнее соединение»), возвращающую готовые массивы или структуры, вместо прямого удаленного конструирования объектов Запрос.