При настройке правил обмена в конфигурации «1С:Конвертация данных 2.0» (КД 2.0) разработчики часто сталкиваются с логической проблемой. Допустим, из базы-источника в базу-приемник переносится документ Заказ покупателя. В ПКО (Правило конвертации объектов) документа в обработчике «После загрузки» прописано условие, которое при определенных обстоятельствах отменяет загрузку документа (устанавливается параметр Отказ = Истина). Однако выясняется, что связанный с документом справочник Контрагенты все равно создается в базе-приемнике, засоряя ее лишними данными.
В этой статье мы подробно разберем, почему так происходит, проанализируем ограничения платформы и рассмотрим 4 проверенных на практике способа решения этой задачи.
Разберем внутренний механизм работы обработчика «Универсальный обмен данными XML». Чтение файла обмена происходит последовательно сверху вниз. В структуре XML-файла данные о связанных объектах (справочник Контрагенты) обычно располагаются и обрабатываются парсером до того, как завершится создание самого документа-владельца. К моменту выполнения обработчика «После загрузки» для документа, объект контрагента уже успешно создан, заполнен и записан в информационную базу приемника.
Когда мы пишем в коде документа Отказ = Истина, платформа отменяет запись документа, но она не отслеживает связи и не откатывает транзакции по созданию элементов справочников, которые были записаны шагом ранее. В итоге в базе остаются «осиротевшие» новые контрагенты.
Рассмотрим рабочие варианты обхода этой проблемы.
Этот архитектурный подход исключает создание «лишних» элементов в базе-приемнике. Суть метода заключается в том, чтобы передавать данные контрагента не как готовую ссылку через стандартное ПКС (Правило конвертации свойства), а в виде набора текстовых параметров объекта, и создавать контрагента программно только после успешной проверки документа.
Выполним следующие шаги:
Контрагент документа Заказ покупателя отключим стандартное правило конвертации (не указываем ПКО).ПараметрыОбъекта.Отказ = Истина. Документ не записывается, а контрагент даже не начинал создаваться.Пример кода в обработчике «После загрузки» для ПКО документа:
Если Не ВыполнитьПроверкуУсловийЗагрузки(Объект) Тогда
Отказ = Истина;
Иначе
// Извлекаем параметры для поиска/создания контрагента
ИННКонтрагента = ПараметрыОбъекта.Получить("Контрагент_ИНН");
КППКонтрагента = ПараметрыОбъекта.Получить("Контрагент_КПП");
Наименование = ПараметрыОбъекта.Получить("Контрагент_Наименование");
СсылкаНаКонтрагента = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ИННКонтрагента);
Если Не ЗначениеЗаполнено(СсылкаНаКонтрагента) Тогда
НовыйКонтрагент = Справочники.Contragents.СоздатьЭлемент();
НовыйКонтрагент.ИНН = ИННКонтрагента;
НовыйКонтрагент.КПП = КППКонтрагента;
НовыйКонтрагент.Наименование = Наименование;
НовыйКонтрагент.Записать();
СсылкаНаКонтрагента = НовыйКонтрагент.Ссылка;
КонецЕсли;
Объект.Контрагент = СсылкаНаКонтрагента;
КонецЕсли;
Этот способ подходит для ситуаций, когда в базе-приемнике допустимо появление временных «битых» ссылок на несуществующие объекты, которые удалятся вместе с отменой загрузки документа.
Схема настройки выглядит так:
Контрагенты устанавливаем флаг «Не создавать новый объект в приемнике, если он НЕ найден».Отказ = Истина. Документ не создается, а «битая» ссылка на контрагента просто исчезает из памяти вместе с объектом документа. В базе не остается никакого мусора.Важное ограничение: этот метод применим только тогда, когда вы точно уверены, что все необходимые контрагенты уже перенесены в приемник ранее, либо их отсутствие является прямым сигналом к тому, что документ не должен быть проведен.
Если решение о необходимости удаления контрагента можно принять только в самом конце сеанса загрузки, мы можем организовать накопление «мусорных» объектов во временной таблице и очистить их при завершении обмена.
Для этого реализуем следующий алгоритм:
Параметры:
ТаблицаКонтрагентов = Новый ТаблицаЗначений;
ТаблицаКонтрагентов.Колонки.Добавить("Контрагент", Новый ОписаниеТипов("СправочникСсылка.Контрагенты"));
ТаблицаКонтрагентов.Колонки.Добавить("Загружен", Новый ОписаниеТипов("Бухущий"));
Параметры.Вставить("ТаблицаКонтрагентов", ТаблицаКонтрагентов);
Загружен = Ложь.Загружен = Истина.Ложь, запускаем процедуру удаления (или пометки на удаление) элементов справочника, предварительно проверив, нет ли на них других ссылок в базе с помощью метода НайтиСсылки().Мы можем попытаться изолировать процесс загрузки каждого отдельного документа и связанных с ним справочников в рамки одной транзакции СУБД.
Реализация выглядит следующим образом:
НачатьТранзакцию().ОтменитьТранзакцию() и устанавливаем Отказ = Истина. При этом все созданные в рамках этой транзакции объекты (включая контрагента) будут удалены из базы автоматически.ЗафиксироватьТранзакцию().Внимание: данный метод имеет существенные ограничения. Он не рекомендуется к использованию при пакетной загрузке больших объемов данных, так как может вызывать блокировки таблиц. Кроме того, если один и тот же новый контрагент используется в нескольких документах из одного файла обмена, откат транзакции по первому документу сотрет контрагента, который критически необходим для загрузки последующих корректных документов.