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