При реализации обмена данными через планы обмена разработчики часто сталкиваются с тем, что стандартный метод платформы ЗаписатьXML(ЗаписьXML, Данные) выгружает объект целиком. Для справочника Номенклатура это означает, что в XML-файл попадут десятки ненужных реквизитов, табличные части, а также служебные свойства. Это приводит к раздуванию размера файла обмена и замедлению процесса интеграции.
В этой статье мы подробно разберем, как решить эту задачу и выгрузить только ключевые поля номенклатуры: уникальный идентификатор (ссылку), код, наименование и артикул. Мы рассмотрим три различных подхода, а также затронем важную тему оптимизации регистрации изменений.
Рассмотрим фрагмент кода, который стандартно используется в модулях планов обмена для выгрузки измененных данных:
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения);
Пока ВыборкаИзменений.Следующий() Цикл
Данные = ВыборкаИзменений.Получить();
// Записать данные в сообщение *** XML-сериализация.
ЗаписатьXML(ЗаписьXML, Данные);
КонецЦикла;
Когда платформа выполняет функцию ЗаписатьXML, она обращается к метаданным переданного объекта (в данном случае СправочникОбъект.Номенклатура) и автоматически сериализует все его свойства. Чтобы изменить это поведение, нам необходимо вмешаться в процесс записи. Выясним, какими способами это можно сделать.
Если обмен разрабатывается без использования сложных правил конвертации и вам нужно быстро решить задачу непосредственно в коде выгрузки, мы можем переписать логику внутри цикла выборки изменений. Проанализируем, как перехватить выгрузку номенклатуры и записать её вручную, тег за тегом.
Заменим стандартный вызов ЗаписатьXML на ветвление по типу объекта:
Пока ВыборкаИзменений.Следующий() Цикл
Данные = ВыборкаИзменений.Получить();
// Проверяем, является ли объект справочником Номенклатура
Если ТипЗнч(Данные) = Тип("СправочникОбъект.Номенклатура") Тогда
// Открываем основной узел объекта номенклатуры
ЗаписьXML.ЗаписатьНачалоЭлемента("CatalogObject.Номенклатура");
// 1. Записываем ссылку (GUID) для однозначной идентификации в приемнике
ЗаписьXML.ЗаписатьНачалоЭлемента("Ref");
ЗаписьXML.ЗаписатьТекст(Строка(Данные.Ссылка.УникальныйИдентификатор()));
ЗаписьXML.ЗаписатьКонецЭлемента();
// 2. Записываем код товара
ЗаписьXML.ЗаписатьНачалоЭлемента("Code");
ЗаписьXML.ЗаписатьТекст(Данные.Код);
ЗаписьXML.ЗаписатьКонецЭлемента();
// 3. Записываем наименование (Description)
ЗаписьXML.ЗаписатьНачалоЭлемента("Description");
ЗаписьXML.ЗаписатьТекст(Данные.Наименование);
ЗаписьXML.ЗаписатьКонецЭлемента();
// 4. Записываем артикул
ЗаписьXML.ЗаписатьНачалоЭлемента("Артикул");
ЗаписьXML.ЗаписатьТекст(Данные.Артикул);
ЗаписьXML.ЗаписатьКонецЭлемента();
// Закрываем основной узел
ЗаписьXML.ЗаписатьКонецЭлемента();
Иначе
// Все остальные объекты регистрируем стандартным образом
ЗаписатьXML(ЗаписьXML, Данные);
КонецЕсли;
КонецЦикла;
Преимущества метода: Простота реализации, высокая скорость работы кода, отсутствие необходимости создавать дополнительные объекты в конфигурации.
Недостатки: Жесткое кодирование структуры тегов. При изменении требований к формату придется переписывать код конфигурации.
Если формат XML-файла строго регламентирован или выгрузка осуществляется во внешнюю систему, ручное формирование тегов может привести к ошибкам валидации. В этом случае на помощь приходит встроенный механизм XDTO (XML Data Transfer Objects).
Рассмотрим пошагово, как реализовать этот подход:
ОбменДанными).НоменклатураСокращенная.Ref (тип string), Code (тип string), Description (тип string) и Article (тип string).После описания схемы в конфигураторе, заменим код выгрузки в цикле плана обмена:
Пока ВыборкаИзменений.Следующий() Цикл
Данные = ВыборкаИзменений.Получить();
Если ТипЗнч(Данные) = Тип("СправочникОбъект.Номенклатура") Тогда
// Получаем фабрику и тип из нашего пакета XDTO
ТипXDTO = ФабрикаXDTO.Тип("http://www.yourcompany.ru/exchange", "НоменклатураСокращенная");
// Создаем экземпляр объекта по схеме
ОбъектXDTO = ФабрикаXDTO.Создать(ТипXDTO);
// Заполняем свойства данными из справочника 1С
ОбъектXDTO.Ref = Строка(Данные.Ссылка.УникальныйИдентификатор());
ОбъектXDTO.Code = Данные.Код;
ОбъектXDTO.Description = Данные.Наименование;
ОбъектXDTO.Article = Данные.Артикул;
// Выполняем запись объекта XDTO в XML
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ОбъектXDTO, "CatalogObject.Номенклатура");
Иначе
ЗаписатьXML(ЗаписьXML, Данные);
КонецЕсли;
КонецЦикла;
Преимущества метода: Автоматический контроль типов данных со стороны платформы, строгое соответствие схеме, красивый и лаконичный код.
Если в вашей конфигурации обмен построен по классической технологии с использованием правил конвертации свойств (ПКС), то писать программный код для обхода реквизитов не потребуется вообще.
Разберем процесс настройки правил конвертации:
Номенклатура.Ссылка, Код, Наименование, Артикул.При использовании КД стандартный механизм выгрузки сам отсечет лишние свойства и запишет в XML только те поля, для которых установлены активные правила.
Ограничение выгружаемых полей на этапе записи XML решает проблему размера итогового файла обмена. Однако остается скрытая проблема производительности: лишние транзакции регистрации изменений.
По умолчанию, если в карточке номенклатуры изменится любой второстепенный реквизит (например, Вес, Производитель или Описание), платформа зарегистрирует изменение этого элемента на узле плана обмена. При очередной выгрузке этот товар попадет в выборку изменений, код отработает, выгрузит сокращенный XML, но сама эта выгрузка будет "холостой", так как ключевые поля (код, артикул, наименование) не менялись.
Для оптимизации этого процесса настроим выборочную авторегистрацию:
Номенклатура и установим для него свойство Авторегистрация в значение Запретить.ПередЗаписью (или ПриЗаписи) для справочника номенклатуры.
Процедура ПередЗаписьюНоменклатурыРегистрация(Источник, Отказ) Экспорт
// Исключаем работу при загрузке данных
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Если это новый элемент - регистрируем его изменения в любом случае
Если Источник.ЭтоНовый() Тогда
ПланыОбмена.ЗарегистрироватьИзменения(ПараметрыСеанса.УзлыОбменаНоменклатуры, Источник);
Возврат;
КонецЕсли;
// Для существующего элемента проверим изменение ключевых реквизитов
СсылкаНаОбъект = Источник.Ссылка;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
// Сравниваем старые значения из базы данных с новыми значениями объекта
Если (Выборка.Код <> Источник.Код)
Или (Выборка.Наименование <> Источник.Наименование)
Или (Выборка.Артикул <> Источник.Артикул) Тогда
// Если изменился хотя бы один из ключевых реквизитов - регистрируем изменения
ПланыОбмена.ЗарегистрироватьИзменения(ПараметрыСеанса.УзлыОбменаНоменклатуры, Источник);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Такой подход позволит сэкономить ресурсы сервера 1С на базах с интенсивным обновлением справочников, так как выгружаться будут только те товары, у которых действительно поменялись критически важные для обмена данные.