Работа с распределенными данными часто требует обращения к одной базе 1С из другой. Использование COM-соединения (Automation) — классический способ решения этой задачи. Однако новички часто сталкиваются с проблемой: запрос в удаленной базе выполняется успешно, но при попытке прочитать результат в текущей базе возникают ошибки или возвращаются пустые значения. Разберем детально, как правильно выгрузить и обработать данные, полученные через COMОбъект.
Когда мы выполняем запрос через глСоединение.NewObject("Запрос"), объект результата запроса или выгруженная таблица значений физически находятся в памяти «той» базы (базы-источника). В нашей текущей базе мы имеем лишь «прокси-ссылку» на этот объект. Прямая попытка выполнить ЗначениеВСтрокуВнутр(vTrans) в текущем сеансе обращается к локальному менеджеру типов, который «не знает», как интерпретировать структуру объекта из другого процесса. Поэтому мы получаем Неопределено или ошибку итератора.
Проанализируем самый быстрый в реализации способ — использование метода ЗначениеВСтрокуВнутр. Важный нюанс: этот метод должен быть вызван через объект соединения, чтобы сериализация прошла в контексте удаленной базы.
Рассмотрим пошаговый алгоритм:
ЗначениеВСтрокуВнутр именно через COM-соединение.ЗначениеИзСтрокиВнутр.Посмотрим на пример кода:
// 1. Инициализируем запрос в COM-базе
vQry = глСоединение.NewObject("Запрос");
vQry.Text = "ВЫБРАТЬ Номенклатура.Наименование, Номенклатура.Код ИЗ Справочник.Номенклатура КАК Номенклатура";
// 2. Получаем таблицу значений (она пока в COM-контексте)
vTrans = vQry.Execute().Unload();
// 3. СЕРИАЛИЗАЦИЯ: вызываем метод через глСоединение!
// Это заставит удаленную базу превратить свою ТЗ в строку
стрТЗ = глСоединение.ЗначениеВСтрокуВнутр(vTrans);
// 4. ДЕСЕРИАЛИЗАЦИЯ: используем локальную функцию
// Теперь в нашей базе появилась полноценная ТаблицаЗначений
ТЗ = ЗначениеИзСтрокиВнутр(стрТЗ);
Важное ограничение: Этот метод безупречно работает только для примитивных типов данных (числа, строки, даты, булево). Если в таблице содержатся ссылки (например, СправочникСсылка), то после десериализации в текущей базе они превратятся в «битые» ссылки, так как UUID объектов в разных базах могут не совпадать, а типы данных не сопоставлены.
Если нам не нужно передавать всю таблицу целиком, а достаточно обработать данные в цикле, мы можем использовать стандартную выборку. Выясним причину, почему часто возникает ошибка «Итератор не определен». В COM-объектах 1С цикл Для каждого напрямую не поддерживается для всех коллекций так же, как внутри системы.
Проанализируем правильный подход с использованием Выбрать() и Следующий():
РезультатЗапроса = vQry.Execute();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Важно: каждое обращение к Выборка.Наименование
// — это отдельный сетевой вызов (RPC), что может быть медленно
Сообщить("Товар из другой базы: " + Выборка.Наименование);
КонецЦикла;
Если же вам необходимо работать именно с таблицей значений без сериализации, используйте обращение по индексу:
vTrans = vQry.Execute().Unload();
КолвоСтрок = vTrans.Count(); // Используем метод COM-объекта
Для Индекс = 0 По КолвоСтрок - 1 Цикл
ТекущаяСтрока = vTrans.Get(Индекс);
Значение = ТекущаяСтрока.Наименование;
// Обработка данных...
КонецЦикла;
Выясним, почему предыдущий метод (цикл) может работать очень долго. Каждый раз, когда вы пишете Выборка.Наименование, программа делает «прыжок» в другую базу, запрашивает значение и возвращается назад. Если в результате 10 000 строк, таких «прыжков» будет десятки тысяч.
Рекомендация: Старайтесь минимизировать количество обращений через точку к COM-объекту. Лучше один раз передать большой объем данных (через строку или массив), чем многократно обращаться за маленькими кусочками.
Метод ЗначениеВСтрокуВнутр является платформозависимым. В современной практике для передачи данных между базами через COM-соединение лучше использовать JSON. Это быстрее и позволяет более гибко управлять типами.
Разберем, как это реализовать:
// В удаленной базе (через COM) выполняем код формирования JSON
// Для этого можно использовать встроенные средства или вызвать функцию общего модуля
ТекстСкрипта =
"
|Функция ПолучитьДанныеВJSON(Запрос)
| ТЗ = Запрос.Execute().Unload();
| ЗаписьJSON = Новый ЗаписьJSON;
| ЗаписьJSON.УстановитьСтроку();
| ЗаписатьJSON(ЗаписьJSON, ТЗ);
| Возврат ЗаписьJSON.Закрыть();
|КонецФункции
|";
// Но проще всего сделать это так:
vQry = глСоединение.NewObject("Запрос");
vQry.Text = "ВЫБРАТЬ Код, Наименование ИЗ Справочник.Валюты";
vРезультат = vQry.Execute().Unload();
// Используем JSON на стороне COM-соединения
// (Предполагается, что в базе-источнике есть доступ к объекту ЗаписьJSON)
vЗаписьJSON = глСоединение.NewObject("ЗаписьJSON");
vЗаписьJSON.УстановитьСтроку();
глСоединение.ЗаписатьJSON(vЗаписьJSON, vРезультат);
СтрокаJSON = vЗаписьJSON.Закрыть();
// Теперь десериализуем в нашей базе
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
МассивДанных = ПрочитатьJSON(ЧтениеJSON); // Получаем массив структур
Если вам нужно передать не только текст, но и идентификаторы объектов, чтобы потом найти их в своей базе, используйте UUID. Ссылочный объект COM-базы бесполезен в текущей базе, но его строковое представление уникально.
Проанализируем пример запроса, возвращающего уникальный идентификатор:
vQry.Text = "ВЫБРАТЬ ВЫРАЗИТЬ(Ссылка КАК СТРОКА) КАК УИД_Строкой, Наименование ИЗ Справочник.Номенклатура";
// Или в цикле получать UUID:
СтрокаУИД = глСоединение.String(Выборка.Ссылка.UUID());
Подведем итог нашим изысканиям. Для эффективной обработки результатов запроса через COM следует придерживаться следующих правил:
ЗначениеВСтрокуВнутр или ЗаписатьJSON) через объект глСоединение.Выборка.Следующий() в цикле по COM-соединению.Get() и Count(), если вы не используете сериализацию.Соблюдение этих принципов позволит вам создавать быстрые и надежные механизмы обмена данными между базами 1С.