При настройке обмена данными часто возникает задача реализовать сложную логику поиска объектов в базе-приемнике. Стандартный поиск по внутреннему идентификатору (ГУИД) подходит не всегда. Рассмотрим типичный сценарий: необходимо перенести справочник "Номенклатура", при этом если у товара в источнике заполнен артикул, то в приемнике его нужно найти по этому артикулу. Если же артикул пуст, поиск должен выполняться по ГУИДу, чтобы обновить существующий элемент, а не создавать дубль.
Попытка решить эту задачу "в лоб" через смену имени правила конвертации объекта (ПКО) в обработчике ПередВыгрузкой самого объекта, как правило, не приводит к успеху. Давайте разберем, почему так происходит и как правильно реализовать такой механизм.
Основная причина неудачи простого переключения ПКО заключается в том, что механизм "Конвертации данных" по умолчанию выполняет поиск по внутреннему идентификатору объекта еще до того, как сработают многие пользовательские обработчики. Этот поиск имеет наивысший приоритет. Чтобы реализовать нашу условную логику, нам нужно взять управление поиском в свои руки. Проанализируем наиболее гибкий и правильный способ решения этой задачи.
Этот метод заключается в использовании одного ПКО для номенклатуры, но с программной настройкой логики поиска внутри обработчика события ПоляПоиска. Такой подход позволяет реализовать многошаговый поиск и сосредоточить всю логику в одном месте, что упрощает дальнейшую поддержку правил.
Разберем реализацию по шагам.
Это критически важный первый шаг. Если его не выполнить, система все равно будет в первую очередь искать объект по ГУИДу, и наш код в ПоляПоиска может не выполниться или выполниться некорректно.
ПКО) для справочника "Номенклатура".ПКО снимите флажок "Искать объект приемника по внутреннему идентификатору".Теперь система не будет выполнять автоматический поиск и полностью доверит эту задачу нашему коду.
Поскольку мы отключили стандартный механизм, нам нужно как-то передать ГУИД из источника в приемник, чтобы использовать его на втором шаге нашего поиска. Также для чистоты кода передадим и артикул. Для этого используются параметры ПКО.
ПКО "Номенклатура" перейдите на вкладку "Параметры".ПередВыгрузкой самого параметра. Выделите параметр "УИД" и нажмите кнопку с многоточием в колонке "Перед выгрузкой".В открывшемся окне введите код для получения ГУИДа:
// Обработчик "ПередВыгрузкой" для параметра "УИД"
Значение = XMLСтрока(Источник.УникальныйИдентификатор());
Аналогично для параметра "АртикулДляПоиска":
// Обработчик "ПередВыгрузкой" для параметра "АртикулДляПоиска"
Значение = Источник.Артикул;
Теперь при выгрузке каждого объекта номенклатуры в XML-файл будут дополнительно выгружены эти два параметра.
Это сердце нашего решения. Вся логика будет находиться в обработчике события ПоляПоиска на основной форме ПКО.
Обработчик ПоляПоиска вызывается системой последовательно несколько раз для одного объекта, пока объект не будет найден или не закончатся варианты поиска. Номер текущей попытки передается в переменной НомерВариантаПоиска. Мы этим воспользуемся для организации двухшагового поиска.
Откройте обработчик ПоляПоиска в вашем ПКО и введите следующий код:
// Проверяем, был ли передан артикул для поиска
Если ЗначениеЗаполнено(ПараметрыОбъекта["АртикулДляПоиска"]) Тогда
// Если артикул есть, то на первом шаге ищем по нему
Если НомерВариантаПоиска = 1 Тогда
// Указываем, по каким полям в приемнике искать.
// В данном примере в приемнике артикул лежит в реквизите "Код".
// Если имя реквизита "Артикул", то укажите его.
СтрокаИменСвойствПоиска = "Код";
// Заполняем структуру со значениями для поиска
СвойстваПоиска.Вставить("Код", ПараметрыОбъекта["АртикулДляПоиска"]);
// Если по артикулу не нашли, то на втором шаге ищем по ГУИДу
ИначеЕсли НомерВариантаПоиска = 2 Тогда
Попытка
// Получаем ссылку по строковому представлению ГУИДа из параметра
УИД = Новый УникальныйИдентификатор(ПараметрыОбъекта["УИД"]);
НайденнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(УИД);
// Если ссылка не пустая и указывает на существующий объект
Если НЕ НайденнаяСсылка.Пустая() И НайденнаяСсылка.ЭтоГруппа = Источник.ЭтоГруппа Тогда
// Присваиваем найденный объект
СсылкаНаОбъект = НайденнаяСсылка;
// Прекращаем дальнейший поиск
ПрекратитьПоиск = Истина;
КонецЕсли;
Исключение
// Обработка возможной ошибки преобразования строки в ГУИД
КонецПопытки;
КонецЕсли;
Иначе
// Если артикул в источнике не был заполнен, то сразу ищем по ГУИДу
Если НомерВариантаПоиска = 1 Тогда
Попытка
УИД = Новый УникальныйИдентификатор(ПараметрыОбъекта["УИД"]);
НайденнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(УИД);
Если НЕ НайденнаяСсылка.Пустая() И НайденнаяСсылка.ЭтоГруппа = Источник.ЭтоГруппа Тогда
СсылкаНаОбъект = НайденнаяСсылка;
ПрекратитьПоиск = Истина;
КонецЕсли;
Исключение
// Обработка возможной ошибки
КонецПопытки;
КонецЕсли;
КонецЕсли;
Проанализируем этот код:
ЗначениеЗаполнено(ПараметрыОбъекта["АртикулДляПоиска"])).НомерВариантаПоиска = 1) мы настраиваем поиск по полю "Код" в приемнике, используя значение из параметра АртикулДляПоиска. Система сама выполнит поиск по этим данным.НомерВариантаПоиска = 2. В этом случае мы вручную пытаемся найти объект по ГУИДу, который также передали через параметр. Если находим — присваиваем результат переменной СсылкаНаОбъект и устанавливаем флаг ПрекратитьПоиск.НомерВариантаПоиска = 1), ищем объект по ГУИДу.Таким образом, мы реализовали гибкую и управляемую логику поиска, которая точно соответствует поставленной задаче. Если ни один из шагов поиска не увенчается успехом, система создаст новый объект, как и положено.