При переносе данных между информационными базами 1С с помощью конфигурации «Конвертация данных 2.1» (КД 2.1) разработчики часто сталкиваются с нестандартными сценариями сопоставления объектов. Классический пример — перенос справочника Номенклатура. Предположим, что в базе-источнике коды номенклатуры имеют префиксы (например, «ПРФ-0000125»), а в базе-приемнике (например, «Управление производственным предприятием» или «ERP») учет ведется без префиксов (например, «00000125»).
Если мы перенесем код напрямую, то в приемнике запишется значение с префиксом источника, что гарантированно сломает автонумерацию справочника. С другой стороны, нам жизненно необходимо сопоставить старые элементы, которые уже были перенесены ранее, именно по коду. Чтобы решить эту задачу, нам потребуется передать исходный код во временном параметре, не записывая его в реквизит Код нового объекта, и выполнить по нему интеллектуальный поиск. В этой статье мы подробно разберем, как правильно реализовать такой алгоритм с помощью обработчика «Поля поиска».
Рассмотрим, как работает стандартный механизм поиска при загрузке данных:
НомерВариантаПоиска.Проанализируем типичную ошибку начинающих разработчиков. Пытаясь выполнить поиск по переданному параметру, они пишут в обработчике следующий код:
СтрокаИменСвойствПоиска = "Пар_Код"; // Ошибка!
Выясним причину, почему этот код приведет к аварийному завершению загрузки. Переменная СтрокаИменСвойствПоиска предназначена исключительно для перечисления через запятую реальных реквизитов (свойств) объекта-приемника, которые физически существуют в метаданных базы-приемника. На основе этой строки ядро КД 2.1 строит динамический запрос к СУБД.
Поскольку у справочника Номенклатура в базе-приемнике нет реквизита с именем Пар_Код, платформа выдаст ошибку о том, что поле не найдено в схеме запроса. Любой поиск по виртуальным параметрам, которые не сопоставлены с реальными реквизитами базы, должен выполняться только программно. Для реализации нестандартного сопоставления объектов также может пригодиться пример настройки поиска при загрузке по дополнительному реквизиту.
Это один из самых коварных «подводных камней» КД 2.1. В обработчике «Поля поиска» коллекция ПараметрыОбъекта по умолчанию содержит только те параметры, для которых в настройках правил конвертации свойств (ПКС) установлен флаг «Поиск».
Если вы передали параметр из базы-источника, но забыли поставить напротив него галочку «Поиск» в таблице ПКС вашего ПКО, то в данном событии при попытке обратиться к коллекции вы получите Неопределено или вызовете ошибку отсутствия ключа в соответствии. Всегда проверяйте коллекцию на заполненность перед получением значений! Для более удобной работы с переменными обработчиков событий и навигации по правилам можно использовать доработанную конфигурацию «Конвертация данных 2.1» с контекстными подсказками.
Рассмотрим пошагово, как настроить надежный поиск номенклатуры по артикулу, наименованию и, в крайнем случае, по очищенному от префикса коду из параметра.
В настройках ПКО для справочника Номенклатура перейдите на вкладку «Параметры» и добавьте параметр Пар_Код. В правилах конвертации свойств (ПКС) настройте передачу значения Источник.Код в этот параметр. Обязательно установите флаг «Поиск» для этого параметра в таблице ПКС! При этом сам реквизит Код передавать в приемник напрямую не нужно, чтобы не нарушать автонумерацию при создании новых позиций.
Перейдем в обработчик события «Поля поиска» на уровне ПКО справочника Номенклатура. Наша задача — настроить четыре последовательных шага поиска:
Пар_Код с предварительным удалением префикса источника.Посмотрим на пример реализации этого алгоритма:
// Шаг 1: Ищем по наиболее точному совпадению (Артикул + Наименование)
Если НомерВариантаПоиска = 1 Тогда
СтрокаИменСвойствПоиска = "Артикул, Наименование";
// Шаг 2: Если первый шаг не дал результатов, пробуем искать только по Наименованию
ИначеЕсли НомерВариантаПоиска = 2 Тогда
СтрокаИменСвойствПоиска = "Наименование";
// Шаг 3: Программный поиск по переданному коду источника (с очисткой от префикса)
ИначеЕсли НомерВариантаПоиска = 3 Тогда
// Обязательно проверяем доступность коллекции параметров
Если ПараметрыОбъекта <> Неопределено Тогда
ИсходныйКод = ПараметрыОбъекта.Получить("Пар_Код");
Если ЗначениеЗаполнено(ИсходныйКод) Тогда
// Предположим, префикс источника имеет вид "ПРФ-" (длина 4 символа)
// Выполним очистку кода перед поиском в базе-приемнике
ОчищенныйКод = ИсходныйКод;
Если Найти(ОчищенныйКод, "-") > 0 Тогда
// Отсекаем префикс и дефис, оставляя только числовую часть
ПозицияДефиса = Найти(ОчищенныйКод, "-");
ОчищенныйКод = Сред(ОчищенныйКод, ПозицияДефиса + 1);
КонецЕсли;
// Выполняем непосредственный поиск в базе приемника
НайденнаяСсылка = Справочники.Номенклатура.НайтиПоКоду(ОчищенныйКод);
Если Не НайденнаяСсылка.Пустая() Тогда
// Объект найден! Записываем его в предопределенную переменную СсылкаНаОбъект
СсылкаНаОбъект = НайденнаяСсылка;
// Прекращаем дальнейшие итерации поиска
ПрекратитьПоиск = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
// Шаг 4: Если все варианты исчерпаны, и объект не найден
Иначе
// Предотвращаем бесконечный цикл поиска и даем КД команду создать новый элемент
ПрекратитьПоиск = Истина;
КонецЕсли;
Проанализируем, почему критически важно правильно позиционировать флаг ПрекратитьПоиск. В ветке обсуждения на форуме один из участников предлагал установить этот флаг в самом конце обработчика вне конструкции Если...КонецЕсли.
Делать так категорически нельзя. Если вы установите ПрекратитьПоиск = Истина глобально для всего обработчика, система выполнит только первый шаг поиска (НомерВариантаПоиска = 1). Если по связке «Артикул + Наименование» ничего не будет найдено, КД сразу же прекратит дальнейшие попытки поиска и перейдет к созданию нового объекта. До шагов с поиском по наименованию и коду алгоритм просто не дойдет.
Запомните правило:
СтрокаИменСвойствПоиска) мы не управляем флагами вручную. Система сама прекратит поиск, если найдет соответствие, или перейдет к следующему шагу (увеличив НомерВариантаПоиска), если не найдет.ПрекратитьПоиск = Истина только в том случае, если мы успешно нашли ссылку и записали ее в СсылкаНаОбъект, либо когда мы дошли до последнего шага алгоритма и хотим принудительно остановить поиск, чтобы начать создание нового элемента.