При настройке обмена данными и правил конвертации часто возникает задача частичного обновления документа. Например, в базе-источнике изменился только один реквизит табличной части (например, цена или номенклатура), а остальные колонки (количество, сумма, аналитика) были скорректированы или заполнены непосредственно в базе-приемнике и должны остаться неизменными.
Однако при стандартной загрузке объектов через механизмы обмена платформа 1С полностью очищает табличную часть методом Очистить() и заполняет её заново данными из входящего пакета. Колонки, которые были исключены из правил выгрузки, в приемнике инициализируются пустыми значениями по умолчанию. Разберем, как правильно реализовать выборочное обновление реквизитов табличной части и избежать потери данных.
Выясним причину, почему нельзя просто отключить перенос остальных колонок в правилах конвертации. Механизм десериализации XML или формата EnterpriseData обрабатывает коллекции целиком:
По этой причине для сохранения существующих в базе-приемнике значений требуется программно восстанавливать данные из существующего объекта до момента окончательной записи.
Рассмотрим базовый вариант, когда количество и порядок строк в базе-источнике и базе-приемнике строго совпадают. В этом случае в правилах конвертации объекта (ПКО) в обработчике «После загрузки» мы можем обратиться к исходной версии объекта через ссылку в базе данных и скопировать значения неизменяемых колонок.
Посмотрим на пример программного кода:
Если НЕ Объект.ЭтоНовый() Тогда
// Получаем количество строк в загруженной табличной части
ВсегоСтрок = Объект.Товары.Количество();
// Перебираем строки и восстанавливаем значения из текущего состояния в базе
Для Индекс = 0 По ВсегоСтрок - 1 Цикл
// Проверяем, что в исходном документе есть строка с таким индексом
Если Индекс < Объект.Ссылка.Товары.Количество() Тогда
// Копируем все реквизиты, кроме обновляемой колонки "Номенклатура"
ЗаполнитьЗначенияСвойств(
Объект.Товары[Индекс],
Объект.Ссылка.Товары[Индекс],
,
"Номенклатура"
);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Метод ЗаполнитьЗначенияСвойств() третьим параметром принимает список исключаемых свойств. Передав туда имя обновляемой колонки, мы оставляем новое загруженное значение нетронутым, а остальные реквизиты возвращаем в исходное состояние.
Проанализируем проблему производительности предыдущего способа: многократное обращение к Объект.Ссылка.Товары внутри цикла порождает множество одиночных запросов к базе данных, что существенно замедляет загрузку больших пакетов документов. Чтобы ускорить процесс, разберем по шагам более эффективный подход через структуру ПараметрыОбъекта.
Если НЕ Объект.ЭтоНовый() Тогда
ПараметрыОбъекта.Вставить("ИсходнаяТаблицаТовары", Объект.Ссылка.Товары.Выгрузить());
КонецЕсли;
ИсходнаяТЗ = Неопределено;
Если ПараметрыОбъекта.Свойство("ИсходнаяТаблицаТовары", ИсходнаяТЗ) И ИсходнаяТЗ <> Неопределено Тогда
Для Индекс = 0 По Объект.Товары.Количество() - 1 Цикл
Если Индекс < ИсходнаяТЗ.Количество() Тогда
ЗаполнитьЗначенияСвойств(
Объект.Товары[Индекс],
ИсходнаяТЗ[Индекс],
,
"Номенклатура"
);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Ориентация только на номер или индекс строки (Индекс) несет высокий риск искажения данных. Если пользователи отсортировали строки в документе, удалили промежуточную строку или добавили новую, сопоставление по позиции приведет к тому, что реквизиты будут перепутаны между разными строками.
Разберем надежный подход, при котором строки связываются по уникальному ключу:
ИдентификаторСтроки (или используется системный КлючСвязи).
ИсходнаяТЗ = Неопределено;
Если ПараметрыОбъекта.Свойство("ИсходнаяТаблицаТовары", ИсходнаяТЗ) И ИсходнаяТЗ <> Неопределено Тогда
Для Каждого СтрокаЗагрузки Из Объект.Товары Цикл
// Ищем исходную строку по идентификатору
СтрокаИсточника = ИсходнаяТЗ.Найти(СтрокаЗагрузки.ИдентификаторСтроки, "ИдентификаторСтроки");
Если СтрокаИсточника <> Неопределено Тогда
ЗаполнитьЗначенияСвойств(СтрокаЗагрузки, СтрокаИсточника, , "Номенклатура, ИдентификаторСтроки");
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если определенная колонка табличной части регулярно живет своей жизнью и модифицируется в другой базе отдельно от основного документа, рекомендуется рассмотреть архитектурные альтернативы:
Документ и ИдентификаторСтроки. На форме документа колонка отображается динамически, а при обмене передаются только записи регистра без перезаписи и блокировки самого документа.Отказ = Истина): В обработчике загрузки предотвращается полная перезапись объекта правилами обмена, а точечное обновление нужного реквизита выполняется программно через вызов метода объекта с записью в режиме РежимЗаписиДокумента.Запись без повторного проведения.