При настройке правил обмена в инструменте «1С:Конвертация данных 2.1» (КД 2.1) разработчики часто сталкиваются с необходимостью реализовать нетривиальную логику сопоставления объектов базы-источника и базы-приемника. Стандартного поиска по уникальному идентификатору (GUID) или равенству кодов/наименований бывает недостаточно. В таких случаях мы прибегаем к написанию произвольного кода в обработчике «Поля поиска» на уровне Правил конвертации объектов (ПКО).
Однако при написании кода «вслепую» прямо в интерфейсе Конвертации данных легко допустить синтаксическую ошибку, которая проявит себя только на этапе загрузки данных в базу-приемник. Одной из самых коварных и распространенных ошибок является сообщение: Ошибка в обработчике события ПоследовательностьПолейПоиска... ОписаниеОшибки = Поле объекта не обнаружено (Наименование). Давайте детально разберем, почему возникает эта ошибка, как правильно работать с коллекциями в КД 2.1 и как настроить полноценную отладку, чтобы больше не совершать подобных промахов.
Давайте проанализируем исходный код, который вызвал ошибку у автора темы. В обработчике «Поля поиска» выполнялся следующий запрос:
Запрос.УстановитьПараметр("Наименование", Лев(СвойстваПоиска.Наименование, 3) + "%");
На первый взгляд код выглядит абсолютно логичным. Мы пытаемся получить значение переданного для поиска наименования, взять его первые три символа и использовать в качестве параметра запроса с оператором ПОДОБНО. Однако платформа 1С на этом шаге аварийно завершает работу с ошибкой обращения к несуществующему полю объекта.
В чем же кроется секрет? Всё дело в типе данных переменной СвойстваПоиска. В КД 2.1 эта переменная является объектом типа Соответствие (Map), а не Структура (Structure).
В платформе «1С:Предприятие» работа с этими коллекциями различается кардинальным образом:
Структура.ИмяСвойства), так как ключи структуры гарантированно являются строками и соответствуют правилам образования идентификаторов.Таким образом, попытка написать СвойстваПоиска.Наименование неизбежно приводит к ошибке Поле объекта не обнаружено, так как у самого объекта Соответствие нет такого встроенного свойства.
Чтобы исправить эту ошибку, нам необходимо изменить способ обращения к элементам коллекции. Мы можем сделать это двумя способами:
Способ 1. Использование квадратных скобок (рекомендуемый):
ИскомоеЗначение = СвойстваПоиска["Наименование"];
Способ 2. Использование метода Получить():
ИскомоеЗначение = СвойстваПоиска.Получить("Наименование");
Оба варианта абсолютно равноправны и безопасны. Если мы перепишем строку установки параметра запроса из примера автора, она примет следующий вид:
Запрос.УстановитьПараметр("Наименование", Лев(СвойстваПоиска["Наименование"], 3) + "%");
После такого простого изменения ошибка обращения к свойству исчезнет.
В описании проблемы автора есть еще один важный нюанс: «В ПКС в источнике пусто, в приемнике Наименование... В обработчике стоит Значение = Источник;».
Давайте разберем, к чему приводит такая конструкция:
Источник внутри обработчиков этого ПКС будет принимать значение Неопределено.Значение = Источник; фактически передает в базу-приемник пустое значение (в данном случае Неопределено).СвойстваПоиска["Наименование"] окажется пустота. Наш запрос попытается выполнить поиск по условию ПОДОБНО "", что не принесет никаких результатов.Если вам необходимо передать конкретное строковое значение в приемник при пустом источнике, следует писать явное присвоение в обработчике ПКС «Перед выгрузкой»:
Значение = "Значение по умолчанию"; // Или любой другой ваш алгоритм получения строки
Если же данные для поиска вообще не связаны напрямую с реквизитами создаваемого объекта-приемника, использовать для этого ПКС реквизита Наименование — не лучшая практика. Для таких целей в КД 2.1 предусмотрен механизм параметров объектов.
Если вам нужно передать из источника в приемник служебные данные, которые нужны исключительно для сопоставления объектов (и которые не должны автоматически записываться в реквизиты найденного элемента), сделайте следующее:
СтрокаДляПоиска.ПараметрыОбъекта:
// ПараметрыОбъекта — это тоже Соответствие, обращаемся через квадратные скобки
ИскомыйТекст = ПараметрыОбъекта["СтрокаДляПоиска"];
Давайте соберем воедино все лучшие практики и напишем надежный, отказоустойчивый шаблон для реализации ручного поиска в обработчике ПКО «Поля поиска». Нам нужно не только написать правильный запрос, но и корректно управлять логикой поиска КД с помощью предопределенных переменных.
Разберем основные переменные, которыми мы должны управлять:
СсылкаНаОбъект — сюда мы должны поместить найденную ссылку на элемент справочника (или документа). Если объект не найден, переменная должна остаться равной Неопределено.ПрекратитьПоиск — булево значение. Если мы нашли объект собственным алгоритмом и больше не хотим, чтобы КД пыталась искать его стандартными механизмами, мы обязаны установить эту переменную в значение Истина.УстанавливатьУОбъектаВсеСвойстваПоиска — очень важный флаг. Если мы нашли объект по частичному совпадению (например, по первым 3 символам наименования), КД по умолчанию попытается перезаписать его наименование тем значением, которое пришло из файла обмена. Чтобы избежать порчи существующих данных в базе-приемнике, рекомендуется устанавливать этот флаг в значение Ложь.Посмотрим на пример готового шаблона кода:
// 1. Проверяем, заполнено ли свойство для поиска в пришедших данных
НаименованиеДляПоиска = СвойстваПоиска["Наименование"];
Если ЗначениеЗаполнено(НаименованиеДляПоиска) Тогда
// Берем первые 3 символа для поиска по маске
СтрокаМаски = Лев(СокрЛП(НаименованиеДляПоиска), 3);
Если СтрДлина(СтрокаМаски) >= 3 Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТарифныеСетки.Ссылка КАК Ссылка,
| ТарифныеСетки.Наименование КАК Наименование
|ИЗ
| Справочник.ТарифныеСетки КАК ТарифныеСетки
|ГДЕ
| ТарифныеСетки.Наименование ПОДОБНО &Маска";
Запрос.УстановитьПараметр("Маска", СтрокаМаски + "%");
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Дополнительная проверка на формат наименования (например, четвертый символ должен быть пробелом)
Если Сред(Выборка.Наименование, 4, 1) <> " " Тогда
Продолжить;
КонецЕсли;
// Если нашли подходящий элемент — фиксируем ссылку
СсылкаНаОбъект = Выборка.Ссылка;
Прервать;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЕсли;
// 2. Управляем поведением КД после завершения нашего поиска
Если ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
// Объект успешно найден в базе-приемнике. Останавливаем дальнейший поиск.
ПрекратитьПоиск = Истина;
// Запрещаем КД затирать оригинальные реквизиты найденного объекта нашими поисковыми значениями
УстанавливатьУОбъектаВсеСвойстваПоиска = Ложь;
Иначе
// Если объект не найден, мы можем либо разрешить КД продолжить стандартный поиск,
// либо принудительно прекратить поиск, что приведет к созданию НОВОГО объекта.
// ПрекратитьПоиск = Истина; // Раскомментируйте, если создание нового объекта обязательно при неудаче ручного поиска
КонецЕсли;
Написание кода в текстовых полях Конвертации данных без возможности поставить точку останова и посмотреть значения переменных — это тяжелый путь, ведущий к множеству скрытых дефектов. На самом деле в КД 2.1 встроен мощный штатный механизм отладки, которым пользуются все профессиональные разработчики.
Давайте разберем по шагам, как запустить отладку вашего кода в обработчике «Поля поиска»:
В базе Конвертации данных перейдите в меню настройки правил обмена. Нажмите на кнопку «Выгрузить код обработчиков». Система предложит вам сохранить текстовый файл (например, Handlers.txt). Сохраните его на свой компьютер.
В комплекте поставки КД 2.1 идет специальная внешняя обработка отладки (обычно она называется УниверсальныйОбменДаннымиXML_Отладка.epf). Откройте конфигуратор вашей базы-приемника, создайте новую внешнюю обработку, скопируйте туда модуль из шаблона отладки и загрузите в него ваш сгенерированный файл Handlers.txt. Платформа создаст полноценные процедуры для каждого вашего обработчика.
Запустите базу-приемник в режиме 1С:Предприятие с включенным режимом отладки. Откройте обработку УниверсальныйОбменДаннымиXML. На вкладке «Параметры отладки» установите галочку «Включить режим отладки обработчиков загрузки» и укажите путь к созданной внешней обработке сгенерированного кода.
Вернитесь в конфигуратор базы-приемника. Найдите в модуле внешней обработки процедуру, отвечающую за поиск вашего объекта (она будет называться примерно так: ПКО_ПоляПоиска_...). Поставьте на строчку с вашим запросом стандартную точку останова клавишей F9.
Начните загрузку данных в обработке обмена. Выполнение программы мгновенно остановится в конфигураторе на вашей точке останова. Теперь вы можете нажать Shift+F9 (Табло) и в реальном времени посмотреть содержимое переменных СвойстваПоиска, ПараметрыОбъекта, проверить результат выполнения запроса и пошагово отследить всю логику работы вашего алгоритма.
Использование этого несложного механизма экономит колоссальное количество времени. Вместо угадывания причин ошибок по логам загрузки, вы сразу видите состояние системы в момент сбоя и можете моментально исправить любые неточности в коде.