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