Работа с технологией COM-соединения в 1С часто преподносит сюрпризы даже опытным разработчикам. Типичная ситуация: один и тот же запрос, выполненный в консоли запросов внутри базы, отрабатывает корректно и выводит все суммы, но при выполнении того же кода через внешнее подключение одна из таблиц (чаще всего связанная с регистрами расчета) возвращает нулевые значения. Проанализируем, почему это происходит, и как правильно настроить передачу параметров для получения верных данных.
Когда мы создаем запрос через COM-соединение, важно понимать, что выполнение кода происходит в контексте вызываемой базы, но управление параметрами осуществляется из основной программы. Рассмотрим стандартную схему инициализации запроса, которую использовал автор темы:
// Инициализация объекта запроса в удаленной базе
Запрос = База.newObject("Запрос");
Запрос.Текст = "ВЫБРАТЬ ..."; // Текст запроса
Основная сложность здесь заключается в передаче ссылочных типов и значений периодов. Если вы передадите в параметр запроса ссылку из текущей базы (например, Справочники.Подразделения.НайтиПоНаименованию("Цех")), запрос в COM-базе не сможет ее распознать, так как внутренние идентификаторы (GUID) в разных базах могут отличаться, даже если это копии с разной историей синхронизации. Правильный подход — поиск объекта непосредственно в контексте COM-соединения.
Рассмотрим, как правильно устанавливать параметры, чтобы запрос «увидел» нужные данные. Проанализируем фрагмент кода:
Запрос.УстановитьПараметр("Подразделение", База.Справочники.Подразделения.НайтиПоКоду("000000062"));
Запрос.УстановитьПараметр("Период", КонецМесяца(ПереданныйОбъект.Дата));
Запрос.УстановитьПараметр("Организация", База.Справочники.Организации.НайтиПоКоду("000000024"));
В данном примере База — это объект COMConnector. Мы выполняем метод НайтиПоКоду непосредственно в удаленной базе, что гарантирует получение валидной ссылки, понятной для движка запросов той базы. Однако главная ошибка часто кроется в параметре Период.
В регистрах расчета 1С (начисления, удержания) есть критически важное поле — ПериодРегистрации. Особенность платформы заключается в том, что данные в этом поле всегда записываются на начало периода (как правило, на начало месяца), независимо от того, какой датой проведен документ начисления.
Выясним причину ошибки автора: в запросе использовалось условие:
ГДЕ УправленческиеНачисления.ПериодРегистрации = НАЧАЛОПЕРИОДА(&Период, ДЕНЬ)
Если в параметр &Период передается КонецМесяца (например, 31.07.2018 23:59:59), то функция НАЧАЛОПЕРИОДА(..., ДЕНЬ) превратит это значение в 31.07.2018 00:00:00. Но реальные записи в регистре расчета за июль хранятся с датой 01.07.2018 00:00:00. В результате прямого сравнения дат запрос не находит ни одной записи, и колонки с суммами заполняются нулями.
Разберем, как ведут себя виртуальные таблицы при работе через COM. В тексте запроса часто используются такие конструкции, как РегистрРасчета.УправленческиеНачисления.ФактическийПериодДействия(...). Посмотрим на пример фильтрации внутри виртуальной таблицы:
ИЗ
РегистрРасчета.УправленческиеНачисления.ФактическийПериодДействия(
ПериодРегистрации = НАЧАЛОПЕРИОДА(&Период, ДЕНЬ)
И Подразделение = &Подразделение
И (НЕ ВидРасчета.ЗачетОтработанногоВремени)
И Результат <> 0) КАК УправленческиеНачисления
Чтобы избежать подобных ошибок, проанализируем следующие рекомендации:
НАЧАЛОПЕРИОДА(&Период, МЕСЯЦ) при работе с периодом регистрации.ЗНАЧЕНИЕ(Перечисление.Имя.Значение), так как это исключает необходимость передачи ссылки через параметр.ВЫБРАТЬ РАЗРЕШЕННЫЕ, чтобы избежать ошибки доступа, которая в COM-соединении может не отобразиться явно, а просто вернуть пустой результат.Если вы столкнулись с тем, что суммы по одной из таблиц не выбираются, пройдем по шагам процесса отладки:
НЕ Основание ССЫЛКА Документ.ЗаказПокупателя. При работе через COM убедитесь, что метаданные в обеих базах идентичны. Если в удаленной базе тип документа называется иначе, условие никогда не выполнится.Важный нюанс: при работе с регистрами расчета через ЛЕВОЕ СОЕДИНЕНИЕ, если условие в секции ГДЕ или в параметрах виртуальной таблицы не находит данных, вся сумма по данной ветке будет NULL. В коде автора используется агрегатная функция СУММА, которая преобразует NULL в 0, что и наблюдалось в итоговой выгрузке.
Рассмотрим правильный вариант установки даты для поиска начислений текущего месяца:
// Вместо КонецМесяца используем НачалоМесяца
Запрос.УстановитьПараметр("Период", НачалоМесяца(ПереданныйОбъект.Дата));
Этот простой шаг синхронизирует время в параметре запроса со временем хранения записей в РегистреРасчета, и данные начнут выбираться корректно.