Как в 1С:Предприятии 7.7 обработать запрос, полученный из базы 1С:Предприятия 8 через OLE/COM

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При организации обмена данными между устаревшими конфигурациями на платформе 1С:Предприятие 7.7 и современными базами на платформе 1С:Предприятие 8.x программисты часто используют прямое COM-соединение (OLE). Одним из наиболее эффективных способов получения данных является выполнение запроса на стороне 1С 8 с последующей обработкой результатов в 1С 7.7.

Однако на этом пути разработчики часто сталкиваются со странным поведением системы: запрос отрабатывает без ошибок, данные в базе-источнике точно есть, но при попытке обойти выборку цикл в 1С 7.7 просто игнорируется. В этой статье мы подробно разберем, почему это происходит, как правильно обходить выборку запроса, а также рассмотрим особенности работы с типами данных при OLE-соединении.

Выясняем причину: почему не работает стандартный цикл обхода

Рассмотрим классический пример кода в 1С 7.7, который вызывает проблему у большинства разработчиков:


ВыборкаБД = ЗапросБД.Выполнить().Выбрать();
Пока ВыборкаБД.Следующий() = 1 Цикл
    // Код обработки данных
    Сообщить(ВыборкаБД.Номер);
КонецЦикла;

При выполнении этого кода программа просто пропускает цикл, даже если метод ВыборкаБД.Количество() возвращает положительное число документов. Почему так происходит?

Дело в различиях типов данных между платформами 1С 7.7 и 1С 8:

  1. В платформе 1С 8 метод Следующий() возвращает системный тип Булево (значения Истина или Ложь).
  2. В платформе 1С 7.7 встроенного типа Булево не существует. При передаче значения типа Булево из внешнего OLE-источника платформа 1С 7.7 интерпретирует Истина как -1, а Ложь — как 0.

Когда мы пишем условие Пока ВыборкаБД.Следующий() = 1, система сравнивает возвращаемое значение (которое равно -1) с единицей. Поскольку -1 <> 1, условие сразу принимает значение «Ложь», и цикл завершается, так и не начавшись.

Правильный обход выборки запроса в 1С 7.7

Чтобы обойти это ограничение, мы можем использовать несколько вариантов написания логического условия в цикле. Рассмотрим наиболее надежные способы.

Способ 1. Проверка на неравенство нулю (рекомендуемый способ)

Поскольку значение Ложь в 1С 7.7 всегда преобразуется в 0, а любое истинное значение будет отличным от нуля, самым безопасным вариантом является проверка на неравенство нулю:


ВыборкаБД = ЗапросБД.Выполнить().Выбрать();
Пока ВыборкаБД.Следующий() <> 0 Цикл
    // Получаем простые типы данных (числа, строки, даты)
    НомерДок = ВыборкаБД.Номер;
    ДатаДок = ВыборкаБД.Дата;
    Сообщить("Обрабатывается документ № " + НомерДок + " от " + ДатаДок);
КонецЦикла;

Способ 2. Проверка на равенство -1

Вы можете явно указать проверку на -1, так как именно это число возвращает OLE-сервер при значении Истина:


Пока ВыборкаБД.Следующий() = -1 Цикл
    // Код обработки
КонецЦикла;

Оба этих способа заставят 1С 7.7 корректно распознавать шаги выборки и заходить в тело цикла.

Особенности работы с типами данных при OLE-обмене

При передаче данных между базами важно понимать, как платформы преобразуют типы данных «на лету». Напрямую через COM-соединение без искажений передаются только простые типы: Число, Строка и Дата.

Если в запросе 1С 8 вы выбираете ссылочные типы (например, Ссылка на справочник или документ), в 1С 7.7 эти поля придут как сложные COM-объекты. Вы не сможете вывести их на форму или записать в базу 1С 7.7 напрямую без предварительного преобразования.

Рассмотрим правила, которые помогут избежать ошибок при работе с типами данных:


// Создаем оригинальные булевы объекты платформы 1С 8
Истина8 = v8.ValueFromStringInternal("{""B"",1}");
Ложь8   = v8.ValueFromStringInternal("{""B"",0}");

// Передаем параметр в запрос
ЗапросБД.УстановитьПараметр("ТолькоПроведенные", Истина8);

Полный пример реализации подключения и выполнения запроса

Ниже приведем готовый к использованию шаблон кода для внешней обработки 1С 7.7, который подключается к базе 1С 8 (например, ЗУП или Бухгалтерии), выполняет запрос с параметрами дат и корректно обходит результаты.


Процедура ВыполнитьЗапросК8()
    
    // 1. Инициализируем COM-соединение
    Попытка
        БазаОЛЕ = СоздатьОбъект("V83.COMConnector");
    Исключение
        Предупреждение("Не удалось создать COMConnector. Проверьте регистрацию библиотеки comcntr.dll!");
        Возврат;
    КонецПопытки;
    
    // Строка подключения (файловый вариант базы 1С 8)
    СтрокаПодключения = "File=""" + СокрЛП(ПутьКБазе) + """; Usr=""" + СокрЛП(Пользователь) + """; Pwd=""" + СокрЛП(Пароль) + """";
    
    Попытка
        v8 = БазаОЛЕ.Connect(СтрокаПодключения);
    Исключение
        Предупреждение("Ошибка подключения к базе 1С 8: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    Сообщить("Подключение установлено успешно!");
    
    // 2. Создаем объект запроса в контексте 1С 8
    ЗапросБД = v8.NewObject("Запрос");
    
    // Задаем текст запроса (используем синтаксис 1С 8)
    ЗапросБД.Текст = 
    "ВЫБРАТЬ
    |   Док.Ссылка КАК Ссылка,
    |   Док.Номер КАК Номер,
    |   Док.Дата КАК Дата,
    |   Представление(Док.Организация) КАК ОрганизацияПредставление
    |ИЗ
    |   Документ.ОтражениеЗарплатыВБухучете КАК Док
    |ГДЕ
    |   Док.Дата МЕЖДУ &НачДата И &КонДата И Док.ПометкаУдаления = ЛОЖЬ";
    
    // 3. Устанавливаем параметры дат с учетом специфики 1С 8 (передаем дату со временем)
    // Конструируем дату начала дня (00:00:00) и конца дня (23:59:59) на стороне 1С 8
    НачДата8 = v8.Date(Год(НачДата), Месяц(НачДата), Число(НачДата), 0, 0, 0);
    КонДата8 = v8.Date(Год(КонДата), Месяц(КонДата), Число(КонДата), 23, 59, 59);
    
    ЗапросБД.УстановитьПараметр("НачДата", НачДата8);
    ЗапросБД.УстановитьПараметр("КонДата", КонДата8);
    
    // 4. Выполняем запрос
    РезультатЗапроса = ЗапросБД.Выполнить();
    ВыборкаБД = РезультатЗапроса.Выбрать();
    
    КоличествоЗаписей = ВыборкаБД.Количество();
    Сообщить("Найдено документов: " + КоличествоЗаписей);
    
    // Если записей нет, прерываем обработку
    Если КоличествоЗаписей = 0 Тогда
        v8 = ""; // Освобождаем память
        Возврат;
    КонецЕсли;
    
    // 5. Обходим выборку (проверка на неравенство нулю!)
    Пока ВыборкаБД.Следующий() <> 0 Цикл
        
        // Получаем значения простых типов напрямую
        ДокНомер = ВыборкаБД.Номер;
        ДокДата  = ВыборкаБД.Дата;
        ОргИмя   = ВыборкаБД.ОрганизацияПредставление;
        
        // Ссылочный объект 1С 8 (будет OLE-объектом в 1С 7.7)
        ДокСсылка = ВыборкаБД.Ссылка; 
        
        Сообщить("Документ № " + ДокНомер + " от " + ДокДата + " (" + ОргИмя + ")");
        
    КонецЦикла;
    
    // 6. Обязательно очищаем ссылки на OLE-объекты для предотвращения утечек памяти
    ВыборкаБД = "";
    РезультатЗапроса = "";
    ЗапросБД = "";
    v8 = ""; // Закрываем сессию подключения
    Сообщить("Обработка данных завершена.");
    
КонецПроцедуры

Советы по оптимизации скорости обмена через OLE

Построчный обход выборки OLE-запроса в цикле Пока ВыборкаБД.Следующий() <> 0 работает медленно, если количество записей исчисляется тысячами. Каждый вызов метода Следующий() и каждое чтение свойства (например, ВыборкаБД.Номер) — это отдельный сетевой/процессный вызов (круг передачи данных между приложениями), требующий времени.

Для оптимизации скорости работы рекомендуем использовать следующие приемы:

  1. Выгрузка в Таблицу значений: Вместо обхода выборки выгружайте результат запроса в таблицу значений на стороне 1С 8 одной командой: ТабЗнач8 = ЗапросБД.Выполнить().Выгрузить();. Хотя объект по-прежнему останется внешним, доступ к строкам по индексам в некоторых случаях работает быстрее, чем итератор выборки.
  2. Сериализация в XML или JSON: Если у вас есть возможность вносить изменения в базу-источник (1С 8), напишите там экспортную функцию, которая выполняет запрос, упаковывает результат в текстовую строку XML или JSON (с помощью механизмов сериализации) и возвращает эту строку в 1С 7.7 за один вызов. В 1С 7.7 вы быстро распарсите полученный текст с помощью встроенных инструментов или внешних компонент.
  3. Использование COMConnector вместо Application: Всегда отдавайте предпочтение объекту V83.COMConnector перед объектом V83.Application. COMConnector не инициализирует тяжелый графический интерфейс пользователя 1С 8, работает в разы быстрее и потребляет значительно меньше оперативной памяти сервера.
← На главную