При интеграции двух информационных баз 1С с помощью технологии COM-соединения разработчики нередко сталкиваются с ошибкой: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов». Подобное исключение возникает в момент выполнения запроса во внешней базе, когда в качестве параметров передаются данные из вызывающей базы. Разберем по шагам, почему возникает эта ошибка, как устроена передача типов через COM и какие существуют способы для правильного получения данных.
Проанализируем типовой сценарий: одна база 1С подключается к другой через объект V83.COMConnector, формирует объект Запрос и пытается передать в него ссылки на справочники (например, Номенклатура или Склад), полученные напрямую из реквизитов формы или объектов текущей базы.
Платформа 1С строго изолирует контексты разных информационных баз. Ссылка на справочник из одной базы является внутренним объектом типа СправочникСсылка.Склады вызывающей базы. Внешняя база через COM ничего не знает об объектах вызывающей стороны: переданный COM-объект ссылки не распознается целевой СУБД как родной ссылочный тип. При попытке сравнить внутреннее ссылочное поле регистра с чужеродным объектом платформа выбрасывает исключение несовместимости типов.
Выясним главное правило: в качестве параметров COM-запроса можно передавать либо примитивные типы (число, строка, дата, булево), либо ссылки, полученные непосредственно в контексте внешней базы (COM-ссылки).
Рассмотрим самый быстрый и простой способ обхода проблемы. Если базы данных содержат одинаковую нормативно-справочную информацию (НСИ) или имеют одинаковые коды элементов, мы можем передавать в запрос не саму ссылку, а строку с кодом или наименованием.
Посмотрим на пример правильного формирования запроса:
КодСклада = СкладТекущейБазы.Код;
КодНоменклатуры = НоменклатураТекущейБазы.Код;
Запрос = ОсновнаяБаза.NewObject("Запрос");
Запрос.Текст =
"ВЫБРАТЬ
| СвободныеОстаткиОстатки.Номенклатура.Наименование КАК Номенклатура,
| СвободныеОстаткиОстатки.ВНаличииОстаток КАК Остаток
|ИЗ
| РегистрНакопления.СвободныеОстатки.Остатки(
| ,
| Номенклатура.Код = &КодНоменклатуры
| И Склад.Код = &КодСклада) КАК СвободныеОстаткиОстатки";
Запрос.УстановитьПараметр("КодНоменклатуры", КодНоменклатуры);
Запрос.УстановитьПараметр("КодСклада", КодСклада);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("В наличии: " + Строка(Выборка.Остаток));
КонецЦикла;
Обратим внимание: обращение через точку к реквизитам Номенклатура.Код в секции параметров виртуальной таблицы приводит к соединению с таблицей справочника на стороне СУБД, однако это полностью избавляет от ошибок несовместимости типов.
Если в базах настроена регулярная синхронизация данных или одна база является копией другой, уникальные идентификаторы объектов совпадают. Поиск по коду или наименованию может быть опасен из-за дублей, поэтому надежнее восстановить ссылку во внешней базе по ее GUID.
Разберем по шагам, как это реализовать:
Строка(Ссылка.УникальныйИдентификатор()).NewObject("УникальныйИдентификатор", СтрокаGUID).ПолучитьСсылку() соответствующего менеджера справочника.Посмотрим на пример кода:
СтрокаГУИД_Склад = Строка(СкладТекущейБазы.УникальныйИдентификатор());
СтрокаГУИД_Номенклатура = Строка(НоменклатураТекущейБазы.УникальныйИдентификатор());
// Восстанавливаем COM-ссылки в контексте удаленной базы
ГУИД_Склад = ОсновнаяБаза.NewObject("УникальныйИдентификатор", СтрокаГУИД_Склад);
СкладCOM = ОсновнаяБаза.Справочники.Склады.ПолучитьСсылку(ГУИД_Склад);
ГУИД_Номенклатура = ОсновнаяБаза.NewObject("УникальныйИдентификатор", СтрокаГУИД_Номенклатура);
НоменклатураCOM = ОсновнаяБаза.Справочники.Номенклатура.ПолучитьСсылку(ГУИД_Номенклатура);
Запрос = ОсновнаяБаза.NewObject("Запрос");
Запрос.Текст =
"ВЫБРАТЬ
| СвободныеОстаткиОстатки.ВНаличииОстаток КАК Остаток
|ИЗ
| РегистрНакопления.СвободныеОстатки.Остатки(
| ,
| Номенклатура = &Номенклатура
| И Склад = &Склад) КАК СвободныеОстаткиОстатки";
Запрос.УстановитьПараметр("Номенклатура", НоменклатураCOM);
Запрос.УстановитьПараметр("Склад", СкладCOM);
Выборка = Запрос.Выполнить().Выбрать();
Еще один универсальный механизм сопоставления объектов между идентичными конфигурациями — использование XML-сериализации:
СтрокаXML = XMLСтрока(СкладТекущейБазы);
ТипСклада = ОсновнаяБаза.XMLТипЗнч(ОсновнаяБаза.Справочники.Склады.ПустаяСсылка());
СкладCOM = ОсновнаяБаза.XMLЗначение(ТипСклада, СтрокаXML);
Полученную переменную СкладCOM можно безопасно использовать в любых операциях сравнения внутри удаленного сеанса.
Проанализируем другие распространенные ошибки, которые часто допускаются при создании запросов к внешним базам:
&Номенк), а в методе УстановитьПараметр передается другое ("Номенклатура"). В результате параметр остается неопределенным.ГДЕ заставляет СУБД сначала рассчитать итоги по всей таблице регистра и лишь затем отобрать нужную запись. Всегда передавайте отборы по измерениям во второй параметр виртуальной таблицы: Остатки(&Период, Условие).Неопределено. В таком случае платформа автоматически обратится к таблице итогов регистра без лишних вычислений среза на дату.Результат = Запрос.Выполнить().Выгрузить() возвращает таблицу значений, у которой нет метода Следующий(). Для обхода таблицы используется цикл Для Каждого Строка Из Результат Цикл, а метод Следующий() применяется исключительно к выборке (Результат.Выбрать()).Важно помнить о механике межпроцессного взаимодействия. Когда мы пишем цикл обхода:
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Номенклатура.Наименование);
КонецЦикла;
Каждое чтение поля через COM и каждое обращение через точку порождает отдельный сетевой и межпроцессный вызов. При обработке сотен или тысяч строк это приводит к катастрофическому падению скорости.
Для ускорения работы рекомендуется сериализовать всю таблицу результатов на стороне COM-базы в единую JSON- или XML-строку, передать одну строку в текущую базу и десериализовать ее локально. Также по окончании работы обязательно освобождайте занятые COM-соединением ресурсы, присваивая переменной подключения значение Неопределено.