Почему в Конвертации Данных 2.1 `ОбъектНайден` = Ложь, хотя объект найден через обработчик "Поля поиска"?

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

При настройке правил обмена в "Конвертации данных 2.1" часто возникает ситуация, когда нужно реализовать сложную логику поиска объектов в базе-приемнике. Для этого используется обработчик события ПоляПоиска у правила конвертации объекта (ПКО). Разберем распространенную проблему: вы написали код в этом обработчике, объект в базе-приемнике успешно находится (в обработчике ПослеЗагрузки параметр Ссылка заполнен), но при этом параметр ОбъектНайден остается в значении Ложь. Это ломает дальнейшую логику, которая на него опирается. Давайте выясним причину такого поведения и рассмотрим, как это исправить.

Анализ причины: почему стандартный механизм не работает

Проблема кроется в логике работы универсальной обработки обмена данными. Когда вы добавляете любой код в обработчик ПоляПоиска, механизм обмена считает, что вы взяли управление поиском полностью на себя и используете собственный, нетиповой алгоритм.

В стандартном коде обработки есть примерно такая проверка:


Если Не ЕстьАлгоритмПоиска Тогда
    // Выполняется стандартный поиск по полям, указанным в ПКО
    СсылкаНаОбъект = НайтиЭлементПоСвойствамПоиска(...);

    // И самое главное - устанавливается флаг "ОбъектНайден"
    ОбъектНайден = ЗначениеЗаполнено(СсылкаНаОбъект);
КонецЕсли;

Как только в обработчике ПоляПоиска появляется хотя бы одна строка кода, переменная ЕстьАлгоритмПоиска становится равной Истина. В результате этот стандартный блок пропускается. Система все еще может использовать заданную вами СтрокаИменСвойствПоиска для поиска объекта и заполнения параметра Ссылка, но автоматическая установка флага ОбъектНайден уже не происходит. Ответственность за это переходит к разработчику.

Даже если ваш код в обработчике выглядит как в официальной справке, это все равно считается пользовательским алгоритмом:


// Обработчик "Поля поиска"
Если НомерВариантаПоиска = 1 Тогда
    СтрокаИменСвойствПоиска = "ЭтоГруппа, ИНН, СтраховойНомерПФР";
Иначе
    СтрокаИменСвойствПоиска = "ЭтоГруппа, Код";
КонецЕсли;

Несмотря на то, что объект по ИНН и СНИЛС будет найден, в обработчике ПослеЗагрузки вы увидите, что ОбъектНайден = Ложь.

Решение 1: Использование параметров `СсылкаНаОбъект` и `ПрекратитьПоиск`

Самый "правильный" способ решения — это полностью реализовать логику поиска внутри обработчика и явно указать результат. Для этого нужно не только задать поля поиска, но и самостоятельно найти объект (например, запросом) и заполнить выходные параметры обработчика.

  1. Напишите запрос для поиска объекта по нужным полям.
  2. Если объект найден, присвойте его ссылку параметру СсылкаНаОбъект.
  3. Установите параметр ПрекратитьПоиск = Истина, чтобы система не продолжала поиск по другим вариантам.

Посмотрим на пример:


// Обработчик "Поля поиска"
Если НомерВариантаПоиска = 1 Тогда
    // Ищем по ИНН и СНИЛС
    Если ЗначениеЗаполнено(Источник.ИНН) И ЗначениеЗаполнено(Источник.СтраховойНомерПФР) Тогда
        // Здесь должен быть ваш код поиска, например, через запрос
        НайденнаяСсылка = НайтиФизЛицоПоИННСНИЛС(Источник.ИНН, Источник.СтраховойНомерПФР);
        
        Если ЗначениеЗаполнено(НайденнаяСсылка) Тогда
            СсылкаНаОбъект = НайденнаяСсылка;
            ПрекратитьПоиск = Истина;
        КонецЕсли;
    КонецЕсли;
ИначеЕсли НомерВариантаПоиска = 2 Тогда
    // Если на первом шаге не нашли, стандартный механизм попробует найти по коду
    СтрокаИменСвойствПоиска = "Код";
КонецЕсли;

При таком подходе, если вы сами найдете объект и заполните СсылкаНаОбъект, флаг ОбъектНайден в последующих обработчиках будет установлен корректно.

Решение 2: Анализ параметра `Ссылка` вместо `ОбъектНайден`

Если вас устраивает, что система сама ищет объект по вашей СтрокаИменСвойствПоиска, и вы не хотите писать запросы, можно пойти более простым путем. Просто измените логику в последующих обработчиках, например, в ПослеЗагрузки.

Вместо проверки ОбъектНайден, проверяйте, заполнена ли ссылка на объект.

Было:


// Обработчик "После загрузки"
Если ОбъектНайден Тогда
    // Логика для найденного объекта (не выполнится)
КонецЕсли;

Стало:


// Обработчик "После загрузки"
Если ЗначениеЗаполнено(Ссылка) Тогда
    // Логика для найденного объекта (теперь работает)
    // Ссылка - это ссылка на найденный или только что созданный объект.
    // Чтобы убедиться, что он именно найден, а не создан,
    // можно сравнить ее со ссылкой загружаемого объекта
    Если НЕ Объект.ЭтоНовый() Тогда
        // ...
    КонецЕсли;
КонецЕсли;

Этот способ прост и эффективен, если вам не принципиально значение самого флага ОбъектНайден.

Решение 3: Принудительная установка флага `ОбъектНайден`

Этот вариант является компромиссом. Он позволяет сохранить остальную логику в обработчике ПослеЗагрузки без изменений. Идея в том, чтобы "починить" значение флага в самом начале обработчика.

Посмотрим на пример:


// Обработчик "После загрузки"

// В самом начале "исправляем" значение флага
Если НЕ ОбъектНайден И ЗначениеЗаполнено(Ссылка) И НЕ Объект.ЭтоНовый() Тогда
    ОбъектНайден = Истина;
КонецЕсли;

// Дальше идет ваша стандартная логика, которая теперь будет работать корректно
Если ОбъектНайден Тогда
    // Какие-то действия с уже существующим объектом...
КонецЕсли;

Итог: выбирайте тот способ, который лучше подходит для вашей задачи. Если поиск сложный и многоступенчатый, лучше использовать первый вариант с явным заполнением СсылкаНаОбъект. Если же вы просто задаете разные наборы полей для поиска, проще и быстрее использовать второй или третий вариант.

← На главную