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