При интеграции устаревающих систем на платформе 1С:Предприятие 7.7 с современными конфигурациями на 1С 8.3 (ERP, Бухгалтерия 3.0, УТ 11) часто используется технология OLE Automation. Несмотря на появление более современных методов обмена (HTTP-сервисы, Web-сервисы), прямое подключение через COM-объект остается популярным "быстрым" решением.
Однако, разработчики часто сталкиваются с неочевидным поведением типов данных при их передаче между версиями платформ. Одной из самых распространенных проблем является обработка циклов и логических значений. Давайте подробно разберем ситуацию, когда метод обхода выборки возвращает странное значение -1, и выясним, как с этим работать эффективно.
Рассмотрим типичный сценарий. Мы пишем код в модуле 1С 7.7. Наша задача — подключиться к базе 1С 8.3, найти группу номенклатуры и перебрать все вложенные элементы.
Код подключения и получения выборки выглядит примерно так:
// Код в 1С 7.7
V8 = СоздатьОбъект("V83.Application"); // Или V83.COMConnector
Попытка
V8.Connect("File=""D:/base/erp"";Usr=""OLE"";Pwd=""pass"";");
Исключение
Сообщить("Ошибка подключения!");
Возврат;
КонецПопытки;
Спр8 = V8.Справочники.Номенклатура;
Группа8 = Спр8.НайтиПоКоду("УП-00001943");
Выборка = Спр8.ВыбратьИерархически(Группа8);
Далее мы пытаемся запустить стандартный цикл обхода, привычный нам по любой версии 1С:
Пока Выборка.Следующий() Цикл
// Обработка элемента
КонецЦикла;
И здесь нас ждет сюрприз: цикл не выполняется, либо выдает ошибку несоответствия типов. Если вывести результат выполнения метода Выборка.Следующий() в окно сообщений, мы увидим значение -1.
Чтобы понять, как исправить код, нужно углубиться в теорию COM-технологий (Microsoft Component Object Model), на которых базируется OLE Automation.
В платформе 1С 8.3 существует полноценный тип Булево (Истина/Ложь). В 1С 7.7 такого типа в явном виде нет, логические операции там обычно оперируют числовыми значениями (1 — Истина, 0 — Ложь) при вычислениях, но в условных операторах контекст понятен.
Однако при передаче данных через OLE-мост происходит преобразование типов (маршалинг). В стандартах OLE Automation логическое значение True (Истина) кодируется как целое число со всеми установленными битами. Для знакового целого числа это соответствует значению -1.
Истина (из 8.3) превращается в -1 (в 7.7).Ложь (из 8.3) превращается в 0 (в 7.7).Оператор цикла Пока в 1С 7.7 ожидает получить логическое условие. Когда мы передаем ему -1, система может вести себя некорректно, так как в 7.7 "истиной" в неявных преобразованиях чаще считается 1.
Самый простой и надежный способ заставить цикл работать — явно сравнивать результат с числовым значением. Поскольку мы выяснили, что "Истина" приходит как "-1", модифицируем код следующим образом:
// Вариант 1: Явное сравнение с -1
Пока Выборка.Следующий() = -1 Цикл
Сообщить(Выборка.Наименование);
КонецЦикла;
Более универсальный вариант, который страхует нас от возможных изменений в реализации COM или использования других языков, — проверять на неравенство нулю (так как Ложь — это всегда 0).
// Вариант 2: Проверка на "не Ложь"
Пока Выборка.Следующий() <> 0 Цикл
Сообщить(Выборка.Наименование);
КонецЦикла;
Оба этих варианта гарантированно работают в среде 1С 7.7.
В исходном примере использовался объект V83.Application. Давайте проанализируем, почему это не всегда лучший выбор.
V83.Application запускает полноценный экземпляр приложения 1С:Предприятие. Это требует много оперативной памяти, времени на запуск и прорисовку (даже если окно скрыто). Для задач обмена данными лучше использовать V83.COMConnector.
Это внутрипроцессный сервер (DLL), который работает значительно быстрее и не создает лишней нагрузки на систему.
// Рекомендуемый способ инициализации
Попытка
V8 = СоздатьОбъект("V83.COMConnector");
Соединение = V8.Connect("File=""D:/base/erp"";Usr=""OLE"";Pwd=""pass"";");
Исключение
Сообщить("Не удалось подключиться через COMConnector");
КонецПопытки;
Обратите внимание: при использовании COMConnector в базе 8.3 не будет доступен модуль приложения и клиентские модули. Весь код, вызываемый из 7.7, должен быть доступен на сервере и во внешнем соединении.
Наладив цикл, мы столкнемся с следующей проблемой: чтение данных.
В 1С 8.3 тип Дата содержит и дату, и время (до секунды). В 1С 7.7 тип Дата содержит только дату, а время хранится отдельно или не используется. При передаче даты из 8.3 в 7.7 могут возникать ошибки преобразования или потеря данных.
Рекомендация: Передавайте даты в строковом формате. Используйте метод Format (или Формат) на стороне 8.3, чтобы получить строку вида "ГГГГММДД", а в 7.7 преобразуйте её обратно.
// Пример получения даты документа
// Ненадежно:
// ДатаДок = Выборка.Дата;
// Надежно (вызываем метод 8-ки String или Format):
СтрокаДаты = Соединение.String(Выборка.Дата); // Вернет строковое представление
// Или используем формат
СтрокаДатыСпец = Соединение.Format(Выборка.Дата, "DF=yyyyMMdd");
Пытаться сохранить ссылку из 8.3 (например, Выборка.Ссылка) в реквизит 7.7 нельзя. Это разные объекты. Сравнивать перечисления через OLE тоже очень медленно.
Лучшая практика: Оперируйте строковыми представлениями или Уникальными Идентификаторами (UUID).
Соединение.String(Выборка.Ссылка.УникальныйИдентификатор()).Соединение.String(Выборка.Статус) или метод XMLString().Давайте посмотрим критически на сам подход перебора выборки через OLE.
Конструкция Пока Выборка.Следующий() ... при работе через COM-соединение является "узким местом". На каждой итерации цикла происходит:
Если в выборке 1000 элементов, вы сделаете 1000 межпроцессных вызовов. Это будет работать очень медленно.
Профессиональный подход: Выполнить запрос целиком на стороне 8.3, выгрузить результат в простую строку (или JSON, если использовать внешние компоненты) и передать эту строку в 7.7 одним вызовом.
Пример алгоритма:
ТаблицаЗначений.| для колонок и ~ для строк).глРазложить или методы работы со строками для парсинга.Пример кода (схематично):
// Этот код выполняем в контексте 8.3 (например, через V8.NewObject("Запрос"))
Запрос = V8.NewObject("Query");
Запрос.Text = "ВЫБРАТЬ Код, Наименование ИЗ Справочник.Номенклатура ГДЕ ЭтоГруппа = ЛОЖЬ";
Результат = Запрос.Execute().Unload();
// Сериализация в строку на стороне 8-ки (придется делать циклом, но он быстрый, т.к. внутри одного процесса)
// Но так как мы пишем код из 7.7, мы управляем объектами 8-ки удаленно:
ВсегоСтрок = Результат.Count();
Ит = 0;
// Внимание: цикл по индексам через OLE тоже медленный, лучше использовать "ЗначениеВСтрокуВнутр"
// или штатные сериализаторы XDTO, если база позволяет.
Для простых задач итерация через Следующий() = -1 допустима. Но для больших объемов данных настоятельно рекомендуем изучить возможность использования HTTP-сервисов. В 1С 7.7 для этого можно использовать объект Microsoft.XMLHTTP или WinHttp.WinHttpRequest.5.1, что позволит обмениваться данными через JSON мгновенно и без блокировок COM-объектов.
Если вы вынуждены использовать OLE для выборки данных из 1С 8.3 в 7.7:
Пока Выборка.Следующий() = -1 Цикл.V83.COMConnector вместо V83.Application.