При организации обмена данными между конфигурациями 1С через COMConnector разработчики часто сталкиваются с ситуацией, когда запрос к внешнему источнику отрабатывает без ошибок, основные реквизиты (наименование, ИНН, КПП) выгружаются успешно, но данные из регистра сведений КонтактнаяИнформация (телефоны, юридические и фактические адреса) возвращаются пустыми.
В этой статье мы подробно проанализируем ситуацию, выясним причину такого поведения запроса и рассмотрим два рабочих способа решения этой проблемы.
Проблема заключается в несоответствии типов данных, передаваемых в параметры запроса. В типовых конфигурациях 1С (например, УПП, Комплексная автоматизация и других) в регистре сведений КонтактнаяИнформация измерения имеют следующий тип данных:
Тип — хранит значение перечисления ПеречислениеСсылка.ТипыКонтактнойИнформации.Вид — хранит ссылку на элемент справочника СправочникСсылка.ВидыКонтактнойИнформации.Если в коде внешней обработки передавать в параметры обычные текстовые строки, как показано ниже:
Запрос.УстановитьПараметр("Т1", "Телефон");
Запрос.УстановитьПараметр("В1", "Телефон контрагента");
Язык запросов 1С при выполнении левого соединения сравнивает ссылку из регистра со строковым значением. Из-за разницы типов левое соединение не находит совпадающих записей, и в результат выгрузки попадают значения NULL (пустые поля).
Разберем по шагам первый способ решения. Чтобы условие соединения сработало корректно, в параметры запроса необходимо передавать не строки, а объекты-ссылки из подключаемой информационной базы.
Рассмотрим подробнее пример реализации данного подхода с подключением через V82.COMConnector (или V83.COMConnector):
COM1с = Новый COMObject("V82.COMConnector");
Попытка
ВнешняяБаза = COM1с.Connect("Srvr=serv1cv82;Ref=workbase;Usr=Пользователь;Pwd=Пароль123");
Исключение
Предупреждение("Ошибка открытия базы!");
Сообщить(ОписаниеОшибки());
ВнешняяБаза = Неопределено;
Возврат;
КонецПопытки;
Запрос = ВнешняяБаза.NewObject("Запрос");
Запрос.Текст = "
|ВЫБРАТЬ
| ПРЕДСТАВЛЕНИЕ(Контрагенты.Ссылка) КАК Ссылка,
| Контрагенты.ИНН КАК ИНН,
| Контрагенты.КПП КАК КПП,
| Контрагенты.Наименование КАК Наименование,
| Контрагенты.НаименованиеПолное КАК НаименованиеПолное,
| КИ_Телефон.Представление КАК Телефон,
| КИ_Адрес.Представление КАК АдресЮридический,
| КИ_Адрес2.Представление КАК АдресФактический,
| Контрагенты.ОсновнойВидДеятельности.Наименование КАК ВидДеятельности,
| Контрагенты.ПометкаУдаления,
| Контрагенты.Родитель
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Телефон
| ПО (КИ_Телефон.Объект = Контрагенты.Ссылка)
| И (КИ_Телефон.Тип = &Т1)
| И (КИ_Телефон.Вид = &В1)
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Адрес
| ПО (КИ_Адрес.Объект = Контрагенты.Ссылка)
| И (КИ_Адрес.Тип = &Т2)
| И (КИ_Адрес.Вид = &В2)
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Адрес2
| ПО (КИ_Адрес2.Объект = Контрагенты.Ссылка)
| И (КИ_Адрес2.Тип = &Т3)
| И (КИ_Адрес2.Вид = &В3)
|ГДЕ
| НЕ Контрагенты.ПометкаУдаления
| И НЕ Контрагенты.ЭтоГруппа";
// Устанавливаем параметры с использованием объектов внешней базы
Запрос.УстановитьПараметр("Т1", ВнешняяБаза.Перечисления.ТипыКонтактнойИнформации.Телефон);
Запрос.УстановитьПараметр("В1", ВнешняяБаза.Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента);
Запрос.УстановитьПараметр("Т2", ВнешняяБаза.Перечисления.ТипыКонтактнойИнформации.Адрес);
Запрос.УстановитьПараметр("В2", ВнешняяБаза.Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента);
Запрос.УстановитьПараметр("Т3", ВнешняяБаза.Перечисления.ТипыКонтактнойИнформации.Адрес);
Запрос.УстановитьПараметр("В3", ВнешняяБаза.Справочники.ВидыКонтактнойИнформации.ФактАдресКонтрагента);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Счетчик = 0;
Пока Выборка.Следующий() Цикл
Счетчик = Счетчик + 1;
Сообщить("Ссылка: " + СокрЛП(Выборка.Ссылка) +
" | ИНН: " + СокрЛП(Выборка.ИНН) +
" | Наименование: " + СокрЛП(Выборка.Наименование) +
" | Телефон: " + СокрЛП(Выборка.Телефон) +
" | Адрес Юр.: " + СокрЛП(Выборка.АдресЮридический) +
" | Адрес Факт.: " + СокрЛП(Выборка.АдресФактический));
Если Счетчик >= 50 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
// Закрываем соединение
ВнешняяБаза = Неопределено;
Посмотрим на альтернативный вариант, позволяющий избежать вызовов объектов внешней базы через COM при установке параметров. Для этого можно использовать конструкцию ЗНАЧЕНИЕ() прямо в тексте запроса.
При использовании этого метода параметры &Т1, &В1 и прочие не требуются, так как ссылки на предопределенные значения перечислений и справочников задаются в самом запросе:
Запрос = ВнешняяБаза.NewObject("Запрос");
Запрос.Текст = "
|ВЫБРАТЬ
| Контрагенты.Наименование КАК Наименование,
| КИ_Телефон.Представление КАК Телефон,
| КИ_Адрес.Представление КАК АдресЮридический
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Телефон
| ПО (КИ_Телефон.Объект = Контрагенты.Ссылка)
| И (КИ_Телефон.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон))
| И (КИ_Телефон.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ТелефонКонтрагента))
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Адрес
| ПО (КИ_Адрес.Объект = Контрагенты.Ссылка)
| И (КИ_Адрес.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес))
| И (КИ_Адрес.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ЮрАдресКонтрагента))
|ГДЕ
| НЕ Контрагенты.ПометкаУдаления
| И НЕ Контрагенты.ЭтоГруппа";
Результат = Запрос.Выполнить();
При реализации выгрузки данных через COM-соединение необходимо учитывать следующие практические рекомендации:
ВнешняяБаза = Неопределено). Это предотвратит зависание фоновых сеансов во внешней информационной базе и освободит занятые лицензии.Ссылка из выборки COM-запроса возвращает COM-объект. Если требуется получить простое текстовое значение (например, наименование родителя или контрагента), используйте в запросе функцию ПРЕДСТАВЛЕНИЕ(Поле).ЮрАдресКонтрагента или ЮридическийАдресКонтрагента в зависимости от конфигурации.