Как правильно получить контактную информацию контрагента из регистра сведений в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При интеграции баз данных через OLE/COM или при обычной выгрузке реквизитов контрагентов разработчики часто сталкиваются с ситуацией, когда данные адресов и телефонов не считываются из регистра сведений КонтактнаяИнформация, хотя визуально в карточке контрагента они заполнены. Разберем типичные ошибки и рассмотрим правильные варианты получения контактных данных.

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


НаборЗаписей = РегистрыСведений.КонтактнаяИнформация.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Объект.Установить(Кл);
НаборЗаписей.Отбор.Тип.Установить(Перечисления.ТипыКонтактнойИнформации.Адрес);
НаборЗаписей.Отбор.Вид.Установить(Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента);
НаборЗаписей.Прочитать();
Для каждого Запись Из НаборЗаписей Цикл
    олеКл.ЮридическийАдрес = Запись.Представление;
КонецЦикла;

Почему отбор не находит запись: основные причины

Выясним причину такого поведения платформы. В приведенном примере переменная Кл формируется следующим образом:


Выборка = Справочники.Контрагенты.Выбрать();
Пока Выборка.Следующий() Цикл
    Кл = Выборка.ПолучитьОбъект();

Здесь кроются ключевые архитектурные ошибки:

  1. Несоответствие типов данных в отборе. Метод ПолучитьОбъект() возвращает значение типа СправочникОбъект.Контрагенты. Измерение Объект регистра сведений КонтактнаяИнформация имеет ссылочный тип (СправочникСсылка.Контрагенты или составной тип ссылок). При передаче в отбор типа «Объект» платформа выполняет строгое сравнение типов и не находит совпадений в таблице базы данных. В отбор необходимо передавать исключительно ссылку: Кл.Ссылка или сразу Выборка.Ссылка.
  2. Избыточное считывание объекта. Вызов Выборка.ПолучитьОбъект() считывает из базы данных все реквизиты, табличные части и блокирует память. Если объект не планируется модифицировать и записывать обратно в базу, использование ПолучитьОбъект() категорически не рекомендуется.
  3. Неэффективное использование набора записей. Объект СоздатьНаборЗаписей() ориентирован на пакетную запись изменений. Для точечного чтения единичной записи он слишком тяжеловесен.

Способ 1. Использование МенеджераЗаписи

Рассмотрим исправление исходного кода с помощью объекта МенеджерЗаписи. Этот объект предназначен для адресации конкретной записи регистра по значениям всех его измерений. Обратите внимание на корректное написание имени метода — СоздатьМенеджерЗаписи (с буквой «д»).


Запись = РегистрыСведений.КонтактнаяИнформация.СоздатьМенеджерЗаписи();
Запись.Объект = Выборка.Ссылка; // Передаем ссылку, а не объект!
Запись.Тип = Перечисления.ТипыКонтактнойИнформации.Адрес;
Запись.Вид = Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента;
Запись.Прочитать();

Если Запись.Выбран() Тогда
    олеКл.ЮридическийАдрес = Запись.Представление;
КонецЕсли;

Метод Выбран() позволяет проверить, существует ли в информационной базе запись с указанными ключевыми полями.

Способ 2. Использование метода Получить() менеджера регистра

Разберем еще более компактный и быстрый вариант для непериодического регистра сведений — вызов метода Получить(). Этот способ не создает промежуточных объектов в памяти:


Отбор = Новый Структура;
Отбор.Вставить("Объект", Выборка.Ссылка);
Отбор.Вставить("Тип", Перечисления.ТипыКонтактнойИнформации.Адрес);
Отбор.Вставить("Вид", Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента);

ДанныеКИ = РегистрыСведений.КонтактнаяИнформация.Получить(Отбор);
ЮрАдрес = ДанныеКИ.Представление;

Метод Получить() возвращает структуру со значениями ресурсов. Если запись с таким набором измерений отсутствует, поля структуры будут содержать значения по умолчанию (для строковых полей — пустую строку).

Способ 3. Оптимальное решение — чтение данных единым запросом

Проанализируем производительность при COM/OLE обмене. Выполнение чтения данных для каждого контрагента в цикле порождает проблему N+1 обращений к базе. При работе через COM-соединение каждый вызов через межпроцессный интерфейс приводит к колоссальным потерям времени.

Наиболее правильным подходом является выборка всех необходимых данных контрагентов вместе с их адресами и телефонами единым запросом через левое соединение:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Контрагенты.Ссылка КАК Контрагент,
    |   Контрагенты.Наименование КАК Наименование,
    |   ЕСТЬNULL(КИ_ЮрАдрес.Представление, """") КАК ЮридическийАдрес,
    |   ЕСТЬNULL(КИ_Телефон.Представление, """") КАК Телефон
    |ИЗ
    |   Справочник.Контрагенты КАК Контрагенты
    |   ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_ЮрАдрес
    |       ПО КИ_ЮрАдрес.Объект = Контрагенты.Ссылка
    |       И КИ_ЮрАдрес.Вид = &ВидЮрАдрес
    |   ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Телефон
    |       ПО КИ_Телефон.Объект = Контрагенты.Ссылка
    |       И КИ_Телефон.Вид = &ВидТелефон
    |ГДЕ
    |   НЕ Контрагенты.ЭтоГруппа";

Запрос.УстановитьПараметр("ВидЮрАдрес", Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента);
Запрос.УстановитьПараметр("ВидТелефон", Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    // Передаем данные в приемник без лишних обращений к СУБД
    олеКл = олеБаза.Справочники.Контрагенты.СоздатьЭлемент();
    олеКл.Наименование = Выборка.Наименование;
    олеКл.ЮридическийАдрес = Выборка.ЮридическийАдрес;
    // ... дальнейшая обработка
КонецЦикла;

Важные замечания по структуре конфигураций

При работе с контактной информацией обязательно учитывайте версию конфигурации:

  1. Проверка предопределенных элементов. Убедитесь, что ссылка Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента действительно существует в метаданных как предопределенный элемент. Если справочник заполнялся пользователями вручную, получение по имени предопределенного вернет Неопределено или вызовет исключение. В таком случае поиск вида следует выполнять по наименованию или уникальному идентификатору.
  2. Конфигурации на базе БСП. В современных конфигурациях («1С:ERP», «Управление торговлей 11», «1С:Бухгалтерия 3.0») контактная информация хранится не в отдельном регистре сведений, а в табличной части справочников (Контрагенты.КонтактнаяИнформация). Для работы с ней используются типовые функции общего модуля УправлениеКонтактнойИнформацией.
← На главную