При настройке обмена данными между конфигурациями 1С (например, при переходе с устаревшей версии 1С:Предприятие 7.7 на современную платформу 1С 8) часто возникает задача распределения загружаемых данных по определенным папкам. Распространенный сценарий: всю входящую номенклатуру из источника необходимо автоматически помещать в специальную группу (папку) в базе-приемнике. При этом сама целевая группа создается непосредственно в приемнике, а информация о ней хранится в реквизитах узла плана обмена.
В этой статье мы подробно разберем, как правильно реализовать данный механизм в конфигурации «Конвертация данных 2.1» (КД 2.1), избежав типичных ошибок производительности и обеспечив безопасность кода при ручной загрузке данных.
В процессе обсуждения на форуме автор предложил передавать код группы из базы-приемника через параметры, а затем искать эту группу в приемнике с помощью функции НайтиПоКоду. Давайте проанализируем, почему этот подход не является оптимальным:
НайтиПоКоду для каждого загружаемого элемента номенклатуры порождает сотни или тысячи избыточных запросов к СУБД. При объеме справочника в десятки тысяч позиций это может критически замедлить процесс импорта.Наиболее правильным и производительным решением является прямая передача ссылки на элемент справочника Номенклатура через глобальную структуру параметров конвертации.
Для начала нам необходимо перехватить узел обмена в момент начала загрузки данных в приемнике и извлечь из его реквизита ссылку на целевую папку. Для этого мы воспользуемся глобальным обработчиком конвертации «После получения информации об узлах обмена».
Этот обработчик выполняется на стороне приемника сразу после того, как из файла обмена прочитаны данные о текущем узле. В контексте этого обработчика нам доступна переменная УзелОбменаЗагрузкаДанных.
Важно предусмотреть защиту от ошибок. Если загрузка будет выполняться интерактивно через обработку УниверсальныйОбменДаннымиXML (например, во время отладки правил), переменная УзелОбменаЗагрузкаДанных может иметь значение Неопределено или содержать пустую ссылку. Прямое обращение к реквизиту в таком случае вызовет аварийное завершение работы системы.
Запишем безопасный и отказоустойчивый код для обработчика «После получения информации об узлах обмена»:
// Проверяем, что загрузка идет в контексте реального плана обмена
Если УзелОбменаЗагрузкаДанных <> Неопределено
И Не УзелОбменаЗагрузкаДанных.Пустая() Тогда
// Используем Попытка-Исключение на случай, если правила запущены
// в базе, где у плана обмена временно отсутствует данный реквизит
Попытка
Параметры.Вставить("ГруппаНоменклатуры", УзелОбменаЗагрузкаДанных.КЭ_ГруппаНоменклатуры);
Исключение
Параметры.Вставить("ГруппаНоменклатуры", Справочники.Номенклатура.ПустаяСсылка());
КонецПопытки;
Иначе
// Если обмен запущен вручную без указания узла, инициализируем параметр пустой ссылкой
Параметры.Вставить("ГруппаНоменклатуры", Справочники.Номенклатура.ПустаяСсылка());
КонецЕсли;
Теперь, когда ссылка на целевую группу надежно сохранена в глобальной структуре Параметры, нам необходимо применить ее к загружаемым объектам. Перейдем в правила конвертации объектов (ПКО) для справочника Номенклатура.
Откроем обработчик события «После загрузки». Данный обработчик выполняется непосредственно перед тем, как объект запишется в базу данных приемника. Здесь мы можем переопределить родителя для загружаемого элемента.
Проанализируем код, который необходимо написать в этом обработчике:
// Проверяем, задана ли целевая папка в параметрах обмена
Если ЗначениеЗаполнено(Параметры.ГруппаНоменклатуры) Тогда
// Переносим только элементы (не трогаем иерархию групп из источника, если это необходимо)
// Также проверяем, чтобы у объекта еще не был заполнен родитель (или перезаписываем принудительно)
Если Не Объект.ЭтоГруппа И Не ЗначениеЗаполнено(Объект.Родитель) Тогда
// Назначаем родителем группу, указанную в плане обмена
Объект.Родитель = Параметры.ГруппаНоменклатуры;
КонецЕсли;
КонецЕсли;
Важное примечание: Если вам требуется принудительно перемещать абсолютно всю номенклатуру (включая группы и подгруппы из источника) внутрь этой папки, условие проверки можно упростить:
Если ЗначениеЗаполнено(Параметры.ГруппаНоменклатуры) Тогда
// Исключаем зацикливание: группа не должна стать родителем самой себе
Если Объект.Ссылка <> Параметры.ГруппаНоменклатуры Тогда
Объект.Родитель = Параметры.ГруппаНоменклатуры;
КонецЕсли;
КонецЕсли;
Несмотря на то, что метод Параметры.Вставить() динамически создает ключ в структуре прямо во время выполнения кода, хорошим тоном разработки в КД 2.1 является явное декларирование параметров.
Для этого выполните следующие действия в интерфейсе конфигурации «Конвертация данных»:
ГруппаНоменклатуры.СправочникСсылка.Номенклатура.Такая настройка задокументирует архитектуру ваших правил и позволит избежать предупреждений при выгрузке и проверке правил обмена.
При массовом переносе элементов в единую папку на стороне приемника могут возникнуть коллизии. Проанализируем возможные проблемы и способы их решения:
Номенклатура в конфигурации-приемнике стоит контроль уникальности кодов «В пределах подчинения», то при переносе множества элементов в одну папку система может выдать ошибку уникальности. В таком случае в обработчике «После загрузки» может потребоваться перегенерация кодов с помощью метода Объект.УстановитьНовыйКод().Записать(). Это означает, что переопределение родителя не потребует повторного обращения к базе данных для перезаписи — объект сохранится в СУБД за один шаг, что гарантирует максимальное быстродействие решения.