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