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