Как в синхронизации через универсальный формат запретить создание нового объекта, если он не найден?

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

При разработке и адаптации правил синхронизации через универсальный формат (EnterpriseData / КД 3.0) разработчики нередко сталкиваются со специфическим поведением механизмов БСП. Типичная задача: при загрузке объекта (например, номенклатуры) необходимо проверить наличие зависимого справочника (например, вида номенклатуры) и, если такого элемента в базе-приемнике нет, отказаться от создания или выполнить альтернативную логику. Однако при попытке найти объект с помощью функции ОбменДаннымиXDTOСервер.СтруктураОбъектаXDTOВДанныеИБ платформа автоматически создает новый элемент в базе данных, даже если было указано действие "ПолучитьСсылку". Выясним причину такого поведения и подробно разберем рабочие варианты решения этой задачи.

Почему функция СтруктураОбъектаXDTOВДанныеИБ создает объект

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

Основное назначение функции ОбменДаннымиXDTOСервер.СтруктураОбъектаXDTOВДанныеИБ — не просто проверка или поиск, а обеспечение ссылочной целостности загружаемых данных. Если передается входящая структура XDTO подчиненного справочника, механизм выполняет поиск по уникальному идентификатору и полям поиска. Если соответствие не найдено, алгоритм БСП принудительно генерирует ссылку и записывает объект-«заглушку», заполненный ключевыми свойствами из XDTO. Это необходимо для того, чтобы ведущий объект не получил битую ссылку в реквизите.

Если для идентификации используется ВариантИдентификации = "ПоУникальномуИдентификатору", создание можно обойти с помощью функции ОбменДаннымиXDTOСервер.СсылкаОбъектаПоУИДОбъектаXDTO. Однако если сопоставление обязательно должно выполняться по полям поиска (например, по наименованию), данный метод не подходит. Разберем практические способы решения этой проблемы.

Способ 1. Прямой поиск запросом к базе данных (рекомендуемый подход)

Рассмотрим наиболее надежный способ проверки. Если в обработчике ПриОбработке правила обработки данных (ПОД) или в обработчиках ПКО требуется только проверить наличие объекта и принять решение о дальнейшей обработке, вызывать механизмы конвертации XDTO избыточно и архитектурно некорректно.

Все необходимые ключевые свойства уже содержатся во входящих данных XDTO. Мы можем выполнить прямой точечный запрос к таблице базы данных или использовать метод менеджера справочника, полностью исключая риск создания лишних объектов и лишних транзакций записи.

Разберем по шагам реализацию проверки через запрос:


// Извлекаем значение ключевого свойства из входящих данных XDTO
НаименованиеДляПоиска = "";
Если ДанныеXDTO.Свойство("ВидНоменклатуры") И ДанныеXDTO.ВидНоменклатуры <> Неопределено Тогда
    ДанныеXDTO.ВидНоменклатуры.Свойство("Наименование", НаименованиеДляПоиска);
КонецЕсли;

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

Важное замечание: типовой механизм поиска EnterpriseData соединяет таблицу справочника с регистром сведений ПубличныеИдентификаторыСинхронизируемыхОбъектов с условием ГДЕ ПубличныеИдентификаторы.Ссылка ЕСТЬ NULL. Это означает, что если элемент с таким наименованием уже был сопоставлен с другим объектом другой базы, типовой поиск посчитает его отсутствующим. Прямой запрос позволяет разработчику самостоятельно определить строгость сопоставления.

Способ 2. Отмена записи через обработчик ПередЗаписьюПолученныхДанных

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

Посмотрим на пример кода, который предотвращает сохранение нового объекта-заглушки:


// Проверяем, является ли объект новым
Если ПолученныеДанные.ЭтоНовый() Тогда
    // Проверяем заполнение неключевых реквизитов, 
    // которые не передаются при выгрузке ссылки
    Если Не ЗначениеЗаполнено(ПолученныеДанные.ТипНоменклатуры) Тогда
        // Сбрасываем переменные для отмены записи
        ПолученныеДанные = Неопределено;
        ДанныеИБ = Неопределено;
    КонецЕсли;
КонецЕсли;

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

Способ 3. Использование параметра УдалятьСозданныеПоКлючевымСвойствам

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

Рассмотрим структуру вызова:


ПараметрыПравила = Новый Структура;
ПараметрыПравила.Вставить("ПравилоКонвертации", ИсходноеПравилоКонвертации);
ПараметрыПравила.Вставить("УдалятьСозданныеПоКлючевымСвойствам", Истина);

Результат = ОбменДаннымиXDTOСервер.СтруктураОбъектаXDTOВДанныеИБ(
    КомпонентыОбмена, 
    ДанныеXDTOВида, 
    ПараметрыПравила, 
    "ПолучитьСсылку"
);

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

← На главную