Работа с платформой 1С:Предприятие 7.7 через OLE-соединение (COM-объект) всегда была сопряжена с рядом технических сложностей. Одной из наиболее распространенных проблем является ситуация, когда один и тот же программный код запроса успешно отрабатывает внутри самой базы (например, во внешней обработке), но возвращает «Ошибка запроса» или пустой результат при вызове через V77.Application. Рассмотрим детально причины такого поведения и разберем по шагам, как сделать запросы к документам стабильными.
Проанализируем ситуацию: когда мы вызываем функцию глобального модуля 1С 7.7 из внешней системы (например, из 1С 8.3), создается отдельный сеанс. В этом сеансе объект Запрос ведет себя иначе из-за особенностей парсинга текста запроса и управления памятью. Основные причины сбоев кроются в использовании локальных переменных, отсутствии агрегатных функций и конфликтах имен в тексте запроса.
Выясним причину на примере типичного некорректного кода:
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с ВыбНачПериода по ВыбКонПериода;
|ОбрабатыватьДокументы все;
|Док = Документ.РасходнаяНакладная.ТекущийДокумент;
|Группировка Док без групп;
|Условие(Док.ВыгрузитьВ83 = 1);
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Возврат \"Ошибка запроса\";
КонецЕсли;
В платформе 1С 7.7 существует критически важная особенность: если в запросе используется группировка (Grouping), но не указана ни одна агрегатная функция (Сумма, Счетчик, Минимум и т.д.), движок запросов может не инициализировать выборку корректно. При работе через OLE это практически всегда приводит к ошибке Выполнить() = 0.
Разберем, как это исправить. Нам необходимо добавить техническую функцию, которая не повлияет на логику, но «заставит» запрос работать. Оптимальным вариантом является функция Счетчик.
Правильный вариант текста запроса:
|Док = Документ.РасходнаяНакладная.ТекущийДокумент;
|Функция КолДок = Счетчик(); // Обязательная добавка для стабильности
|Группировка Док;
Проанализируем влияние языковых настроек. При вызове 1С 7.7 как OLE-сервера, интерпретатор команд может некорректно обрабатывать русские ключевые слова в тексте запроса (такие как Период, Условие, Группировка), если региональные настройки вызывающей и вызываемой системы различаются. Использование английских аналогов гарантирует понимание команды на уровне ядра системы.
Рекомендуем заменить ключевые слова на следующие:
Period вместо ПериодCondition вместо УсловиеGrouping вместо ГруппировкаAll вместо ВсеВ обычном модуле 1С 7.7 запрос легко «видит» переменные ВыбНачПериода и ВыбКонПериода. Однако в OLE-контексте связь с областью видимости локальных переменных часто теряется. Рассмотрим способ решения этой проблемы — вклеивание значений дат непосредственно в строку запроса.
Вместо передачи имени переменной, используем функцию Формат() для преобразования даты в строку вида ДД.ММ.ГГГГ (или формат, принятый в вашей базе), чтобы запрос получил готовое значение.
Пример формирования текста:
ТекстЗапроса = "
|Period from " + Формат(ВыбНачПериода, "Д ДДММГГГГ") + " to " + Формат(ВыбКонПериода, "Д ДДММГГГГ") + ";
|ОбрабатыватьДокументы все;
|Док = Документ.РасходнаяНакладная.ТекущийДокумент;
|Grouping Док;
|Condition(Док.ВыгрузитьВ83 = 1);";
Посмотрим на ситуацию, описанную в сообщениях форума: если вы выполняете несколько запросов последовательно, используя одни и те же имена переменных внутри текста (например, Док), 1С 7.7 может кэшировать структуру запроса некорректно. Это приводит к тому, что первый запрос проходит, а второй — падает с ошибкой.
Рекомендация: Для каждого типа документа в разных функциях используйте уникальные имена переменных внутри текста запроса. Например, ДокРН для расходных накладных и ДокПН для приходных. Также перед созданием нового объекта Запрос желательно явно обнулять переменную: Запрос = 0; Запрос = СоздатьОбъект("Запрос");.
Рассмотрим самую серьезную архитектурную ошибку: возврат самого объекта Запрос из функции через OLE (как показано в сообщении №11 форума). Объект Запрос в 1С 7.7 является сложным внутренним объектом, который плохо сериализуется для передачи во внешние системы.
При попытке вызвать методы Группировка() или ПолучитьПараметр() у такого объекта на стороне 1С 8.3, вы с большой вероятностью получите ошибку доступа к памяти или разрыв соединения.
Единственно верный способ передачи данных:
ТаблицаЗначений.Запрос.Выгрузить(ТЗ, 0, 0);.ТаблицаЗначений.Таблицы значений 7.7 прекрасно передаются через COM-интерфейс и позволяют легко перебирать строки во внешней системе.
Проанализируем и соберем все рекомендации в один надежный пример кода, который будет вызываться из 1С 8.3:
Функция глПолучитьДанныеДокументов(ДатаНач, ДатаКон) Экспорт
Перем Запрос, ТекстЗапроса, ТЗРезультат;
Запрос = СоздатьОбъект("Запрос");
// Используем английскую нотацию и вклеиваем даты
ТекстЗапроса = "
|Period from " + Формат(ДатаНач, "Д ДДММГГГГ") + " to " + Формат(ДатаКон, "Д ДДММГГГГ") + ";
|ОбрабатыватьДокументы все;
|ДокРН = Документ.РасходнаяНакладная.ТекущийДокумент;
|СтатусВыгрузки = Документ.РасходнаяНакладная.ВыгрузитьВ83;
|Функция СчетчикДок = Счетчик(ДокРН);
|Grouping ДокРН;
|Condition(СтатусВыгрузки = 1);";
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
// Записываем лог или выводим предупреждение
Возврат "Ошибка";
КонецЕсли;
// Выгружаем в таблицу значений перед возвратом
ТЗРезультат = СоздатьОбъект("ТаблицаЗначений");
Запрос.Выгрузить(ТЗРезультат, 0, 0);
Возврат ТЗРезультат;
КонецФункции
Соблюдение этих правил — агрегатные функции, английская нотация, уникальные имена переменных и возврат через Таблицу Значений — позволит вам забыть о «мистических» ошибках запросов в 1С 7.7 при интеграции с современными системами.