При настройке обмена данными в конфигурации «Конвертация данных 2.1» часто возникает задача трансформации данных «на лету». Типичный пример: выгрузка остатков товаров, где для номенклатуры необходимо подставить не текущий артикул из справочника, а новое значение, хранящееся в отдельном Регистре Сведений. Если справочник содержит сотни тысяч позиций, стандартные методы «запрос в ПКС» приведут к катастрофическому падению скорости выгрузки. В этой статье мы разберем, как реализовать эту задачу эффективно.
Рассмотрим стандартный, но неверный подход. Мы могли бы в ПКО (Правило конвертации объектов) Номенклатура для свойства Артикул в обработчике ПередВыгрузкой написать запрос к регистру сведений. Однако, если выгружается 200 000 остатков, система выполнит 200 000 отдельных обращений к базе данных. Это создаст огромную нагрузку на SQL-сервер и затянет процесс выгрузки на часы. Наша задача — получить все данные одним запросом и передать их по цепочке правил.
Это наиболее корректный способ с точки зрения архитектуры КД 2.1. Мы переносим логику получения нового артикула на уровень ПВД (Правила выгрузки данных).
Шаг 1. Настройка ПВД
Для правила выгрузки остатков (например, по регистру ТоварыНаСкладах) установим способ выборки «Произвольный алгоритм». Это позволит нам полностью контролировать текст запроса. В тексте запроса мы соединим таблицу остатков с нашим регистром сведений, где хранятся новые артикулы.
Проанализируем пример кода в обработчике ПередОбработкой в ПВД:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Количество,
| ЕСТЬNULL(СоответствиеАртикулов.НовыйАртикул, ТоварыНаСкладахОстатки.Номенклатура.Артикул) КАК АртикулДляВыгрузки
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СоответствиеАртикулов КАК СоответствиеАртикулов
| ПО ТоварыНаСкладахОстатки.Номенклатура = СоответствиеАртикулов.Номенклатура";
ВыборкаДанных = Запрос.Выполнить().Выгрузить();
Шаг 2. Передача данных в ПКО
Теперь нам нужно передать АртикулДляВыгрузки в правило конвертации номенклатуры. Для этого в ПВД в обработчике ПередВыгрузкойОбъекта мы заполняем структуру ИсходящиеДанные.
// В ПВД ПередВыгрузкойОбъекта
Если ИмяПКО = "Номенклатура" Тогда
ИсходящиеДанные = Новый Структура;
ИсходящиеДанные.Вставить("Артикул", Объект.АртикулДляВыгрузки);
КонецЕсли;
Шаг 3. Прием данных в ПКО Номенклатура
В самом ПКО Номенклатура для свойства Артикул необходимо указать, что данные могут приходить «извне». В обработчике ПередВыгрузкой ПКС (Правила конвертации свойства) пропишем логику приоритета:
// Если данные переданы через ИсходящиеДанные из ПВД, они попадут во ВходящиеДанные ПКО
Если ВходящиеДанные <> Неопределено И ВходящиеДанные.Свойство("Артикул") Тогда
Значение = ВходящиеДанные.Артикул;
Иначе
// Если выгружаем номенклатуру просто так, берем стандартный артикул
Значение = Источник.Артикул;
КонецЕсли;
Важно: Не забудьте поставить галочку «Получить из входящих данных» в настройках ПКС Артикул.
Если выгрузка происходит не только через конкретное ПВД, но и «по ссылкам» из разных документов, метод с ИсходящиеДанные может быть трудоемким (придется менять все ПВД). В этом случае применим метод кэширования.
Разберем алгоритм по шагам:
ПередВыгрузкойДанных создадим глобальную переменную (через структуру Параметры) и заполним её один раз всеми соответствиями артикулов.Номенклатура будем обращаться к этой переменной.Пример кода в ПередВыгрузкойДанных (глобальный обработчик):
Запрос = Новый Запрос("ВЫБРАТЬ Номенклатура, НовыйАртикул ИЗ РегистрСведений.СоответствиеАртикулов");
ТЗ = Запрос.Выполнить().Выгрузить();
// Создаем соответствие для максимально быстрого поиска по ключу-ссылке
Параметры.Вставить("КэшАртикулов", Новый Соответствие);
Для Каждого Стр Из ТЗ Цикл
Параметры.КэшАртикулов.Вставить(Стр.Номенклатура, Стр.НовыйАртикул);
КонецЦикла;
Теперь в ПКО Номенклатура, в ПКС Артикул, мы пишем всего одну строку кода в событии ПередВыгрузкой:
НовыйАртикул = Параметры.КэшАртикулов.Получить(Источник.Ссылка);
Если НовыйАртикул <> Неопределено Тогда
Значение = НовыйАртикул;
КонецЕсли;
Этот метод работает молниеносно, так как получение значения из Соответствия в памяти практически не занимает времени по сравнению с SQL-запросом.
Если нам нужно выгружать строго только ту номенклатуру, по которой есть остатки, и при этом жестко управлять параметрами выгрузки, мы можем использовать метод ВыгрузитьОбъект внутри цикла обхода выборки в ПВД.
Проанализируем ситуацию: в ПВД с произвольным алгоритмом мы получили запрос с остатками. Вместо того чтобы позволить системе автоматически выгружать ссылки, мы делаем это вручную:
// В ПВД Произвольный алгоритм
Запрос = Новый Запрос(ТекстЗапросаССоединением);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Формируем структуру данных для ПКО номенклатуры
ДанныеДляПКО = Новый Структура("Артикул", Выборка.АртикулДляВыгрузки);
// Выгружаем саму номенклатуру программно
ВыгрузитьОбъект(Выборка.Номенклатура, , ДанныеДляПКО, "Номенклатура");
// Здесь также может быть логика выгрузки самого регистра остатков или документа
// ...
КонецЦикла;
Метод ВыгрузитьОбъект хорош тем, что он позволяет передать структуру ДанныеДляПКО, которая внутри ПКО будет доступна как ВходящиеДанные.
Разберем важный момент, связанный с поиском объектов в базе-приемнике. Если в правилах конвертации номенклатуры поиск настроен по артикулу, то после его подмены «на лету» система может не найти существующий объект в приемнике и создаст дубль с новым артикулом.
Чтобы этого избежать, рекомендуем:
Мы рассмотрели три эффективных способа подмены данных при выгрузке больших массивов в Конвертации данных 2.1. Выбор метода зависит от ваших условий:
Использование этих подходов позволит вам сократить время обмена данными в десятки раз и избежать типичных ошибок перегрузки сервера 1С.