Как правильно передавать параметры и выполнять запросы через COM-соединение в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При интеграции двух информационных баз 1С с помощью технологии COM-соединения разработчики нередко сталкиваются с ошибкой: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов». Подобное исключение возникает в момент выполнения запроса во внешней базе, когда в качестве параметров передаются данные из вызывающей базы. Разберем по шагам, почему возникает эта ошибка, как устроена передача типов через COM и какие существуют способы для правильного получения данных.

В чем причина ошибки несовместимости типов?

Проанализируем типовой сценарий: одна база 1С подключается к другой через объект V83.COMConnector, формирует объект Запрос и пытается передать в него ссылки на справочники (например, Номенклатура или Склад), полученные напрямую из реквизитов формы или объектов текущей базы.

Платформа 1С строго изолирует контексты разных информационных баз. Ссылка на справочник из одной базы является внутренним объектом типа СправочникСсылка.Склады вызывающей базы. Внешняя база через COM ничего не знает об объектах вызывающей стороны: переданный COM-объект ссылки не распознается целевой СУБД как родной ссылочный тип. При попытке сравнить внутреннее ссылочное поле регистра с чужеродным объектом платформа выбрасывает исключение несовместимости типов.

Выясним главное правило: в качестве параметров COM-запроса можно передавать либо примитивные типы (число, строка, дата, булево), либо ссылки, полученные непосредственно в контексте внешней базы (COM-ссылки).

Способ 1. Фильтрация по коду, артикулу или наименованию

Рассмотрим самый быстрый и простой способ обхода проблемы. Если базы данных содержат одинаковую нормативно-справочную информацию (НСИ) или имеют одинаковые коды элементов, мы можем передавать в запрос не саму ссылку, а строку с кодом или наименованием.

Посмотрим на пример правильного формирования запроса:


КодСклада = СкладТекущейБазы.Код;
КодНоменклатуры = НоменклатураТекущейБазы.Код;

Запрос = ОсновнаяБаза.NewObject("Запрос");
Запрос.Текст = 
"ВЫБРАТЬ
|   СвободныеОстаткиОстатки.Номенклатура.Наименование КАК Номенклатура,
|   СвободныеОстаткиОстатки.ВНаличииОстаток КАК Остаток
|ИЗ
|   РегистрНакопления.СвободныеОстатки.Остатки(
|       ,
|       Номенклатура.Код = &КодНоменклатуры
|           И Склад.Код = &КодСклада) КАК СвободныеОстаткиОстатки";

Запрос.УстановитьПараметр("КодНоменклатуры", КодНоменклатуры);
Запрос.УстановитьПараметр("КодСклада", КодСклада);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить("В наличии: " + Строка(Выборка.Остаток));
КонецЦикла;

Обратим внимание: обращение через точку к реквизитам Номенклатура.Код в секции параметров виртуальной таблицы приводит к соединению с таблицей справочника на стороне СУБД, однако это полностью избавляет от ошибок несовместимости типов.

Способ 2. Получение ссылки по Уникальному Идентификатору (UUID)

Если в базах настроена регулярная синхронизация данных или одна база является копией другой, уникальные идентификаторы объектов совпадают. Поиск по коду или наименованию может быть опасен из-за дублей, поэтому надежнее восстановить ссылку во внешней базе по ее GUID.

Разберем по шагам, как это реализовать:

  1. Получаем строковое представление GUID из ссылки текущей базы через метод Строка(Ссылка.УникальныйИдентификатор()).
  2. Во внешней базе создаем объект идентификатора с помощью NewObject("УникальныйИдентификатор", СтрокаGUID).
  3. Получаем валидную COM-ссылку внешней базы методом ПолучитьСсылку() соответствующего менеджера справочника.
  4. Передаем полученную COM-ссылку в параметры запроса.

Посмотрим на пример кода:


СтрокаГУИД_Склад = Строка(СкладТекущейБазы.УникальныйИдентификатор());
СтрокаГУИД_Номенклатура = Строка(НоменклатураТекущейБазы.УникальныйИдентификатор());

// Восстанавливаем COM-ссылки в контексте удаленной базы
ГУИД_Склад = ОсновнаяБаза.NewObject("УникальныйИдентификатор", СтрокаГУИД_Склад);
СкладCOM = ОсновнаяБаза.Справочники.Склады.ПолучитьСсылку(ГУИД_Склад);

ГУИД_Номенклатура = ОсновнаяБаза.NewObject("УникальныйИдентификатор", СтрокаГУИД_Номенклатура);
НоменклатураCOM = ОсновнаяБаза.Справочники.Номенклатура.ПолучитьСсылку(ГУИД_Номенклатура);

Запрос = ОсновнаяБаза.NewObject("Запрос");
Запрос.Текст = 
"ВЫБРАТЬ
|   СвободныеОстаткиОстатки.ВНаличииОстаток КАК Остаток
|ИЗ
|   РегистрНакопления.СвободныеОстатки.Остатки(
|       ,
|       Номенклатура = &Номенклатура
|           И Склад = &Склад) КАК СвободныеОстаткиОстатки";

Запрос.УстановитьПараметр("Номенклатура", НоменклатураCOM);
Запрос.УстановитьПараметр("Склад", СкладCOM);

Выборка = Запрос.Выполнить().Выбрать();

Способ 3. Сериализация ссылок через XMLСтрока

Еще один универсальный механизм сопоставления объектов между идентичными конфигурациями — использование XML-сериализации:


СтрокаXML = XMLСтрока(СкладТекущейБазы);
ТипСклада = ОсновнаяБаза.XMLТипЗнч(ОсновнаяБаза.Справочники.Склады.ПустаяСсылка());
СкладCOM = ОсновнаяБаза.XMLЗначение(ТипСклада, СтрокаXML);

Полученную переменную СкладCOM можно безопасно использовать в любых операциях сравнения внутри удаленного сеанса.

Типичные ошибки при написании запросов через COM

Проанализируем другие распространенные ошибки, которые часто допускаются при создании запросов к внешним базам:

  1. Несоответствие имен параметров: в тексте запроса указывается одно имя (например, &Номенк), а в методе УстановитьПараметр передается другое ("Номенклатура"). В результате параметр остается неопределенным.
  2. Условия в блоке ГДЕ вместо параметров виртуальной таблицы: фильтрация остатков в предложении ГДЕ заставляет СУБД сначала рассчитать итоги по всей таблице регистра и лишь затем отобрать нужную запись. Всегда передавайте отборы по измерениям во второй параметр виртуальной таблицы: Остатки(&Период, Условие).
  3. Передача даты: если требуются актуальные остатки на текущий момент, первый параметр виртуальной таблицы остатков можно оставить пустым или передать Неопределено. В таком случае платформа автоматически обратится к таблице итогов регистра без лишних вычислений среза на дату.
  4. Путаница между выборкой и таблицей значений: вызов Результат = Запрос.Выполнить().Выгрузить() возвращает таблицу значений, у которой нет метода Следующий(). Для обхода таблицы используется цикл Для Каждого Строка Из Результат Цикл, а метод Следующий() применяется исключительно к выборке (Результат.Выбрать()).

Оптимизация производительности: избегаем COM-вызовов в цикле

Важно помнить о механике межпроцессного взаимодействия. Когда мы пишем цикл обхода:


Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Номенклатура.Наименование);
КонецЦикла;

Каждое чтение поля через COM и каждое обращение через точку порождает отдельный сетевой и межпроцессный вызов. При обработке сотен или тысяч строк это приводит к катастрофическому падению скорости.

Для ускорения работы рекомендуется сериализовать всю таблицу результатов на стороне COM-базы в единую JSON- или XML-строку, передать одну строку в текущую базу и десериализовать ее локально. Также по окончании работы обязательно освобождайте занятые COM-соединением ресурсы, присваивая переменной подключения значение Неопределено.

← На главную