Как реализовать поиск документа в базе-приемнике по реквизитам табличной части в 1С:Конвертация данных

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

При настройке правил обмена в конфигурации «1С:Конвертация данных 2.1» (КД 2.1) разработчики часто сталкиваются с ограничениями стандартного механизма поиска. Типовой функционал позволяет легко сопоставлять объекты по уникальному идентификатору (GUID) или по полям поиска (таким как Номер, Дата, Организация). Однако что делать, если бизнес-логика требует найти существующий документ в базе-приемнике по соответствию организации и, например, номенклатуре или штрихкоду из первой строки его табличной части?

В этой статье мы подробно разберем, почему стандартный поиск по табличным частям не работает «из коробки», изучим архитектурные особенности загрузки данных в КД 2.1 и реализуем надежное решение этой задачи с помощью параметров выгрузки и кастомного поиска запросом.

Почему стандартный поиск по табличным частям не работает напрямую?

Для понимания сути проблемы проанализируем архитектуру работы обработчиков КД 2.1 при импорте данных. Процесс загрузки любого объекта из файла XML разделен на строго последовательные фазы:

  1. Чтение заголовка объекта и его ключевых свойств. На этом этапе система считывает только те поля, которые помечены как «Поля поиска».
  2. Поиск объекта в базе данных приемника. Выполняются обработчики ПриПоиске и ПоляПоиска. Именно здесь система пытается найти существующую ссылку в информационной базе.
  3. Создание или инициализация объекта. Если объект найден, он считывается из базы; если нет — создается новый пустой объект.
  4. Заполнение реквизитов и табличных частей. Только на этом этапе XML-парсер начинает читать данные табличных частей из файла и записывать их в объект-приемник.

Таким образом, в момент работы обработчиков поиска табличные части документа-источника в базе-приемнике еще физически не прочитаны из файла. Обратиться к ним напрямую через свойства объекта или файлы обмена на этапе поиска невозможно. Единственный архитектурно верный путь — передать нужные поисковые значения из табличной части источника в виде дополнительных параметров самого объекта.

Рассмотрим по шагам, как настроить такую схему обмена.

Шаг 1. Создание и настройка ПКС для передачи параметра

Первым делом нам необходимо выгрузить значение из табличной части источника в специальный параметр, который будет путешествовать вместе с заголовком объекта в XML-файле. Для этого выполним следующие действия в правилах конвертации объектов (ПКО) нашего документа:

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

Пример кода для обработчика ПередВыгрузкой ПКС:


Если Источник.Товары.Количество() > 0 Тогда
    // Получаем реквизит из первой строки табличной части "Товары"
    Значение = Источник.Товары[0].Номенклатура;
Иначе
    Значение = Неопределено;
КонецЕсли;

Шаг 2. Настройка стандартных полей поиска

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

Шаг 3. Реализация поиска в обработчике «Поля поиска» ПКО

Теперь перейдем к самому главному — написанию алгоритма сопоставления на стороне приемника. Откроем свойства ПКО нашего документа и перейдем в обработчик события ПоляПоиска. Нам нужно решить несколько задач:

Проанализируем пример кода для обработчика ПоляПоиска:


// Проверяем, инициализирована ли структура параметров
Если ПараметрыОбъекта <> Неопределено Тогда
    
    // Получаем переданный нами параметр и организацию из полей поиска
    ИскомаяНоменклатура = ПараметрыОбъекта.Получить("Параметр_НоменклатураПервойСтроки");
    Организация = СвойстваПоиска["Организация"];
    
    // Поиск выполняем только если ключевые поля заполнены
    Если ЗначениеЗаполнено(ИскомаяНоменклатура) И ЗначениеЗаполнено(Организация) Тогда
        
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
            |   Док.Ссылка КАК Ссылка
            |ИЗ
            |   Документ.РеализацияТоваровУслуг КАК Док
            |ГДЕ
            |   Док.Проведен = ИСТИНА
            |   И Док.Организация = &Организация
            |   И Док.Товары.Номенклатура = &Номенклатура";
            
        Запрос.УстановитьПараметр("Организация", Организация);
        Запрос.УстановитьПараметр("Номенклатура", ИскомаяНоменклатура);
        
        РезультатЗапроса = Запрос.Выполнить();
        
        Если Не РезультатЗапроса.Пустой() Тогда
            Выборка = РезультатЗапроса.Выбрать();
            Выборка.Следующий();
            
            // Передаем ссылку на найденный документ в систему
            СсылкаНаОбъект = Выборка.Ссылка;
            
            // Сообщаем КД 2.1, что объект успешно найден и дальнейший поиск не требуется
            ПрекратитьПоиск = Истина;
        КонецЕсли;
        
    КонецЕсли;
    
КонецЕсли;

Сложный сценарий: Поиск по нескольким строкам (массиву значений)

Рассмотрим более сложную ситуацию. Предположим, что нам нужно найти элемент справочника Номенклатура в приемнике, сопоставив его по массиву штрихкодов, хранящихся в его табличной части. Очевидно, что поиск по первой строке здесь не поможет, так как порядок строк может отличаться. Мы можем масштабировать наше решение и передать в параметр целый массив.

Разберем, как передать массив значений через ПКС в обработчике ПередВыгрузкой:


МассивШтрихкодов = Новый Массив;

// Обходим все строки табличной части и собираем штрихкоды
Для Каждого СтрокаТЧ Из Источник.Штрихкоды Цикл
    Если ЗначениеЗаполнено(СтрокаТЧ.Штрихкод) Тогда
        МассивШтрихкодов.Добавить(СтрокаТЧ.Штрихкод);
    КонецЕсли;
КонецЦикла;

// Передаем весь массив в значение параметра
Значение = МассивШтрихкодов;

Теперь посмотрим, как обработать этот массив на стороне загрузки в событии ПоляПоиска ПКО справочника:


// Исключаем поиск для групп справочника
Если СвойстваПоиска["ЭтоГруппа"] = 1 Тогда
    СтрокаИменСвойствПоиска = "Наименование,ЭтоГруппа";
Иначе
    Если ПараметрыОбъекта <> Неопределено Тогда
        
        СписокШтрихкодов = ПараметрыОбъекта.Получить("Параметр_МассивШтрихкодов");
        
        Если СписокШтрихкодов <> Неопределено И СписокШтрихкодов.Количество() > 0 Тогда
            
            Запрос = Новый Запрос;
            Запрос.Текст = 
                "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
                |   Номенклатура.Ссылка КАК Ссылка
                |ИЗ
                |   Справочник.Номенклатура КАК Номенклатура
                |ГДЕ
                |   Номенклатура.Штрихкод В (&СписокШтрихкодов)";
                
            Запрос.УстановитьПараметр("СписокШтрихкодов", СписокШтрихкодов);
            
            РезультатЗапроса = Запрос.Выполнить();
            Выборка = РезультатЗапроса.Выбрать();
            
            Если Выборка.Следующий() Тогда
                СсылкаНаОбъект = Выборка.Ссылка;
                ПрекратитьПоиск = Истина;
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;
КонецЕсли;

Безопасность кода и предотвращение ошибок

Для того чтобы разработанные правила обмена работали стабильно и не приводили к аварийному завершению сеанса обмена данными, рекомендуем придерживаться следующих правил:

  1. Уникальность имен параметров. Всегда давайте параметрам поиска префиксы (например, Параметр_). Это гарантирует, что имя параметра случайно не совпадет с именем физического реквизита объекта в базе-приемнике, предотвращая ошибку «Поле объекта не обнаружено».
  2. Проверка на Неопределено. Структура ПараметрыОбъекта может быть не инициализирована в некоторых сценариях работы (например, при интерактивном вводе на основании). Всегда оборачивайте код извлечения параметров в проверку Если ПараметрыОбъекта <> Неопределено Тогда.
  3. Множественные результаты запроса. Если ваш поисковый запрос потенциально может вернуть несколько документов-аналогов, обязательно определите бизнес-логику выбора: брать ли самый первый (оператор ПЕРВЫЕ 1 в запросе), самый свежий по дате или выдавать предупреждение в лог регистрации.

Альтернатива: Как эта задача решается в Конвертации данных 3.0?

Если вы планируете переводить интеграционные процессы на современную технологию «1С:Конвертация данных 3.0» (КД 3.0), работающую через формат EnterpriseData, то описанный выше обходной путь вам не понадобится.

В КД 3.0 архитектура сопоставления объектов принципиально переработана. При импорте данных в обработчике ПриИдентификацииОбъекта в модуле менеджера обмена разработчику доступна переменная ДанныеXDTO. Это полностью десериализованный XML-пакет, который уже содержит в себе все табличные части импортируемого объекта.

Посмотрим на концептуальный пример кода идентификации в КД 3.0:


// Пример логики сопоставления в КД 3.0
Если ДанныеXDTO.Свойство("Товары") Тогда
    Для Каждого СтрокаТовары Из ДанныеXDTO.Товары Цикл
        // Мы можем напрямую читать элементы табличной части из XDTO-пакета
        ИскомаяНоменклатура = СтрокаТовары.Номенклатура;
        
        // Здесь выполняется стандартный запрос поиска в БД приемника...
        Прервать; // Например, ищем только по первой строке
    КонецЦикла;
КонецЕсли;

Таким образом, переход на КД 3.0 позволяет отказаться от «костылей» с искусственным созданием параметров на стороне выгрузки и описывать всю логику сопоставления исключительно на стороне базы-приемника, повышая общую чистоту и сопровождаемость кода интеграции.

← На главную