Как запретить обновление (перезапись) документа в базе-приемнике при обмене данными через XML

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

При настройке обмена данными между конфигурациями (например, Управление торговлей и Бухгалтерия предприятия) с помощью «1С:Конвертация данных 2.0», часто возникает задача: запретить изменение объекта в базе-приемнике, если он соответствует определенным критериям. Например, если бухгалтер уже проверил документ в приемнике и установил в нем какой-то флаг или изменил статус, мы не хотим, чтобы повторная выгрузка из источника затерла эти изменения.

В этой статье мы подробно разберем, как реализовать такую логику правильно, используя стандартные механизмы обработчиков событий, и почему стоит избегать сложных «велосипедов» с использованием COM-соединений.

Механика работы обработчиков в Конвертации данных 2.0

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

Многие начинающие разработчики совершают ошибку, пытаясь проверить значения реквизитов через параметр Объект. Рассмотрим, почему это не всегда эффективно и как получить доступ к «старым» данным, которые уже хранятся в базе приемника до момента записи.

Способ 1. Использование обработчика «После загрузки» (Рекомендуемый)

Это самый гибкий и мощный способ. Рассмотрим ситуацию: данные уже прочитаны из файла и помещены в переменную Объект, но они еще не записаны в информационную базу. В этом обработчике нам доступны два ключевых параметра:

  1. Объект — это данные, пришедшие из источника (уже измененные).
  2. Ссылка — это ссылка на текущий объект, который уже существует в вашей базе (со старыми данными).

Важный нюанс: при обращении к реквизитам через Ссылка.ИмяРеквизита, 1С обращается напрямую к данным в таблицах БД, а не к переменной в памяти. Это позволяет нам сравнить то, что «было», с тем, что «пришло».

Разберем пример кода для обработчика После загрузки. Допустим, мы не хотим обновлять документ, если в базе-приемнике он уже проведен:


Если ОбъектНайден Тогда
    // Обращаемся к данным в базе по ссылке
    Если Ссылка.Проведен Тогда
        // Устанавливаем флаг отказа от загрузки объекта
        Отказ = Истина;
        Сообщить("Документ " + Ссылка + " проведен в приемнике. Загрузка отменена.");
    КонецЕсли;
КонецЕсли;

Если мы установим Отказ = Истина, объект не будет записан, и данные в базе-приемнике останутся нетронутыми. Мы можем использовать более сложные условия, например, проверку табличных частей, как в примере автора темы. Проанализируем ситуацию, когда нужно проверить наличие записей в табличной части ВыплатаЗаработнойПлаты:


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

Способ 2. Использование параметра «НеЗамещатьОбъект» в «При загрузке»

Рассмотрим другой вариант. Если нам нужно запретить перезапись объекта целиком, независимо от значений конкретных полей (просто по факту того, что объект уже существует), мы можем использовать обработчик При загрузке.

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


// В обработчике "При загрузке"
Если ОбъектНайден Тогда
    // Если объект уже есть, просто не будем его трогать
    НеЗамещатьОбъект = Истина;
КонецЕсли;

Этот метод хорош для нормативно-справочной информации (НСИ), где база-приемник является эталонной по наполнению реквизитов.

Почему COM-соединение в обработчиках — это плохая практика?

Проанализируем решение, предложенное в сообщении №6. Автор пытался создать COMConnector внутри обработчика Перед выгрузкой, чтобы подключиться к приемнику и проверить наличие документа там. Выясним, почему это «костыль»:

  1. Производительность: Установление COM-соединения — очень длительная операция. Если у вас выгружается 1000 документов, система 1000 раз будет пытаться авторизоваться в другой базе. Обмен, который мог длиться 5 минут, растянется на часы.
  2. Лицензирование: Каждое COM-подключение занимает клиентскую лицензию 1С. Вы можете просто исчерпать лимит лицензий в разгар рабочего дня.
  3. Стабильность: Если база-приемник недоступна или занята, выгрузка из источника прервется с ошибкой.

Вывод: всегда старайтесь переносить логику проверки на сторону того узла, который владеет информацией. Если нужно проверить состояние приемника — делайте это в обработчиках загрузки в самом приемнике.

Как передать дополнительные данные для проверки из источника?

Иногда решение о записи в приемнике должно приниматься на основе данных, которых в самом объекте приемника нет. В этом случае мы можем использовать коллекцию ПараметрыОбъекта.

Разберем по шагам:

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

Резюме

Мы выяснили, что наиболее эффективным и правильным способом отказа от передачи изменений является использование обработчика После загрузки в сочетании с параметром Ссылка. Это позволяет сравнивать текущее состояние базы данных с входящими данными из файла обмена без лишних затрат ресурсов. Помните, что использование Отказ = Истина в загрузке — это штатный механизм, который предотвращает только запись объекта, не нарушая целостность всего процесса обмена.

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

← На главную