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