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