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