При интеграции нескольких конфигураций 1С или обмене данными через механизм COM-соединения (часто называемый OLE) разработчики регулярно сталкиваются с необходимостью выполнения запросов во «внешней» базе. Одной из самых распространенных проблем в этой ситуации является передача параметров в запрос, особенно если этими параметрами являются коллекции — массивы или списки значений. Рассмотрим подробнее, почему возникают ошибки при использовании стандартных методов и как правильно организовать работу с виртуальными таблицами остатков и оборотов через COM.
Проанализируем типичную ситуацию. Разработчик создает объект Запрос во внешней базе, пишет текст запроса к виртуальной таблице РегистрБухгалтерии.Хозрасчетный.Обороты и пытается передать в него массив видов субконто или массив счетов. Ошибка часто кроется в первой же строке инициализации массива:
// ОШИБОЧНЫЙ ВАРИАНТ
ВС = Новый Массив; // Массив создается в ТЕКУЩЕЙ базе
ВС.Добавить(БазаОткрыта.ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты);
Запрос.УстановитьПараметр("ВС", ВС);
В данном примере ВС — это объект типа Массив, принадлежащий контексту текущей информационной базы. Несмотря на то, что внутрь этого массива мы добавляем ссылки из внешней базы (БазаОткрыта...), сам контейнер остается «чужим» для объекта Запрос, который живет внутри БазаОткрыта. При попытке выполнить такой код система выдаст ошибку несоответствия типов или проигнорирует параметр, так как внешняя база не может корректно обработать локальный объект памяти текущей базы.
Выясним, как сделать так, чтобы внешняя база «понимала» передаваемые ей данные. Единственный верный способ — это создавать любые коллекции (Массив, СписокЗначений, ТаблицаЗначений), которые будут переданы в параметры запроса, непосредственно в контексте той базы, к которой мы подключены. Для этого используется метод NewObject() объекта COM-соединения.
Разберем по шагам правильный алгоритм действий:
БазаОткрыта.NewObject("Массив").Посмотрим на пример правильной реализации:
// ПРАВИЛЬНЫЙ ВАРИАНТ
// Создаем массив именно во внешней базе
ВС = БазаОткрыта.NewObject("Массив");
// Добавляем виды субконто из метаданных внешней базы
ВС.Добавить(БазаОткрыта.ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты);
ВС.Добавить(БазаОткрыта.ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры);
// Передаем массив в запрос
Запрос.УстановитьПараметр("ВС", ВС);
// То же самое касается и массива счетов
МассивСчетов = БазаОткрыта.NewObject("Массив");
МассивСчетов.Добавить(БазаОткрыта.ПланыСчетов.Хозрасчетный.НайтиПоКоду("60.01"));
Запрос.УстановитьПараметр("МассивСчетов", МассивСчетов);
Этот подход гарантирует, что менеджер запросов внешней базы получит объект, который находится в его адресном пространстве, и сможет успешно обработать входящие данные.
Часто после исправления ошибки с типами данных разработчики замечают, что выполнение кода происходит крайне медленно или система вовсе «зависает». Рассмотрим подробнее причины этого явления и способы борьбы с ним. Основная проблема COM-соединения — это маршалинг (процесс преобразования данных при передаче между процессами). Каждый вызов через точку (например, Выборка.Субконто1) — это отдельный сетевой или межпроцессный вызов, который занимает время.
Проанализируем ситуацию: если ваш запрос возвращает 1000 строк и в каждой строке вы обращаетесь к 5 полям через Выборка.Следующий(), вы совершаете 5000 обращений через COM-интерфейс. Это и создает эффект «зависания».
Чтобы избежать этой проблемы, используйте следующий метод:
Посмотрим на пример эффективного получения данных:
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Теперь у нас есть объект ТаблицаЗначений во внешней базе.
// Вместо обхода в цикле, мы можем сериализовать её для быстрой передачи.
// Или обращаться к ней, но помнить о накладных расходах.
Важный совет: При работе с виртуальными таблицами (такими как Обороты) через COM, всегда старайтесь максимально ограничивать период (&НачПер, &КонПер) и устанавливать жесткие фильтры по счетам. Это уменьшит объем данных, передаваемых через границу процессов.
При передаче массива &ВС (ВидыСубконто) в виртуальную таблицу, помните, что порядок элементов в массиве определяет порядок колонок Субконто1, Субконто2 и так далее в результате запроса. Если вы передаете массив из двух элементов (Контрагенты и Договоры), то в Субконто1 всегда будут контрагенты, а в Субконто2 — договоры, независимо от того, как они настроены в плане счетов внешней базы. Это очень удобный механизм для унификации получения данных из разных баз, где настройки счетов могут отличаться.
Если вам нужно передать в запрос конкретную ссылку, которую вы знаете в текущей базе, но не знаете, как её найти во внешней (кроме как по коду), лучше использовать UUID. Это самый надежный способ сопоставления объектов. Рассмотрим пример:
// Получаем строковый GUID из текущей базы
СтрGUID = Строка(СсылкаВТекущейБазе.УникальныйИдентификатор());
// Находим объект во внешней базе
ВнешняяСсылка = БазаОткрыта.Справочники.Контрагенты.ПолучитьСсылку(БазаОткрыта.NewObject("УникальныйИдентификатор", СтрGUID));
Если Не ВнешняяСсылка.Пустая() Тогда
// Объект найден, его можно передавать в параметр
Запрос.УстановитьПараметр("Контрагент", ВнешняяСсылка);
КонецЕсли;
Таким образом, соблюдение правила «создавай объект там, где он используется» в сочетании с минимизацией обращений через точку позволит вам создавать быстрые и надежные механизмы взаимодействия между базами 1С через COM-соединение.