Как обновить только один реквизит в табличной части документа при конвертации данных, не затирая остальные поля?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При работе с инструментом «1С:Конвертация данных 2.1» программисты часто сталкиваются с задачей точечного обновления данных. Если с реквизитами шапки документа всё достаточно просто — мы выставляем флаг поиска по внутреннему идентификатору и отключаем обработку ненужных свойств, то с табличными частями (ТЧ) ситуация сложнее. По умолчанию механизм КД настроен на полную замену коллекции: при загрузке старые строки удаляются, и записываются новые. Рассмотрим подробнее, как обойти это ограничение и научить систему изменять только одну колонку в существующей таблице.

Проблема идентификации строки в табличной части

Первое, что мы должны проанализировать — это способ сопоставления строк. В отличие от самих документов или справочников, у строк табличной части в платформе 1С нет своего GUID (Уникального Идентификатора). Поэтому система «не знает», какая строка в базе-приемнике соответствует строке из файла выгрузки. Если мы просто передадим одну колонку, КД либо очистит всю ТЧ, либо добавит новые строки к существующим, либо затрет все остальные колонки в найденных строках, сделав их пустыми.

Разберем по шагам три основных способа решения этой задачи: через настройки правил (декларативный), через программную обработку (императивный) и через использование входящих данных.

Способ 1. Использование механизма поиска в ПКГС (Правила конвертации групп свойств)

Этот метод считается наиболее правильным с точки зрения архитектуры КД, так как он задействует штатные механизмы поиска. Мы должны явно указать системе, по каким полям идентифицировать строку в табличной части.

Рассмотрим алгоритм настройки:

  1. В ПКО (Правиле конвертации объектов) для вашего документа переходим к настройке ПКГС (вашей табличной части).
  2. Для самой группы свойств (папки ТЧ) необходимо снять флаг «Отключить обработку правила».
  3. Внутри группы свойств оставляем включенными только те реквизиты, которые участвуют в поиске (например, Номенклатура, Характеристика, Склад) и тот реквизит, который мы хотим изменить.
  4. Для всех остальных реквизитов внутри ТЧ, которые не должны меняться, устанавливаем флаг «Отключить обработку правила».
  5. Важный момент: на тех реквизитах, по которым мы ищем строку (например, на Номенклатура), нужно обязательно поставить галочку «Поиск» (Поиск объекта при загрузке по свойству).
  6. Для самой таблицы (ПКГС) устанавливаем флаг «Не очищать табличную часть приемника». В коде обработчика это эквивалентно установке НеОчищать = Истина;.

Проанализируем ситуацию: теперь при загрузке система будет перебирать строки в приемнике, искать совпадение по ключевым полям (например, по номенклатуре) и, найдя строку, обновит в ней только тот реквизит, обработка которого не отключена. Однако этот метод работает корректно только если в табличной части нет дублей ключевых полей.

Способ 2. Программное слияние данных в обработчиках загрузки

Если стандартных настроек поиска недостаточно или структура ТЧ слишком сложная, мы можем прибегнуть к программному методу. Этот способ позволяет нам полностью контролировать процесс замены данных, сравнивая объект в памяти с данными из базы.

Выясним причину, почему это надежнее: мы можем прочитать состояние объекта из базы данных Объект.Ссылка непосредственно перед его модификацией. Выполним следующие действия в обработчике «При загрузке» на уровне ПКО документа:


// Сохраняем текущую таблицу из базы данных во временную переменную
Если Не Объект.ЭтоНовый() Тогда
    ТзСтарая = Объект.Ссылка.Товары.Выгрузить();
    ПараметрыОбъекта.Вставить("СтараяТаблицаТоваров", ТзСтарая);
КонецЕсли;

Далее, в обработчике «После загрузки», мы выполняем слияние. На этом этапе в Объект.Товары уже находятся данные из файла, но они «неполные» (остальные колонки затерты). Мы восстановим их:


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

Этот подход гарантирует, что все колонки, кроме целевой, останутся в том состоянии, в котором они были в базе-приемнике до момента загрузки.

Способ 3. Передача данных через коллекцию «Входящие данные»

Если мы хотим максимально «чистого» обмена без передачи всей структуры ТЧ, можно воспользоваться механизмом ВходящиеДанные. Это позволит передать в приемник только те изменения, которые необходимы, не затрагивая штатные алгоритмы конвертации свойств ТЧ.

Рассмотрим, как это реализовать:

  1. В базе-источнике в обработчике «Перед выгрузкой» документа формируем список изменений (например, таблицу значений или массив структур), содержащий идентификатор строки и новое значение реквизита.
  2. Передаем эту структуру в ВходящиеДанные.
  3. В базе-приемнике в обработчике «После загрузки» считываем эти данные и точечно модифицируем объект.

Пример кода в обработчике «После загрузки» приемника:


Если ВходящиеДанные <> Неопределено Тогда
    Для Каждого ДанныеСтроки Из ВходящиеДанные.ИзмененияТЧ Цикл
        ПараметрыПоиска = Новый Структура("Номенклатура", ДанныеСтроки.Номенклатура);
        СтрокиОбъекта = Объект.Товары.НайтиСтроки(ПараметрыПоиска);
        
        Для Каждого СтрокаТЧ Из СтрокиОбъекта Цикл
            СтрокаТЧ.НужныйРеквизит = ДанныеСтроки.НовоеЗначение;
        КонецЦикла;
    КонецЦикла;
КонецЕсли;

Важные системные настройки обработки обмена

Посмотрим на ситуацию шире: иногда даже идеально настроенные правила не работают из-за настроек самой обработки «Универсальный обмен данными XML». При загрузке данных в интерфейсе обработки есть критически важный флаг «Очищать табличные части объектов».

Важно: если эта галочка установлена, то она имеет приоритет над настройками внутри XML-файла правил. Система сначала очистит коллекцию ТЧ у объекта, а потом начнет загружать свойства. Для решения нашей задачи эту галочку нужно обязательно снять в интерфейсе перед началом загрузки.

Также стоит помнить про настройку «Замещать существующие объекты» в ПКО. Если она выключена, то объект в приемнике вообще не будет изменен, если он уже найден по идентификатору. Для нашей задачи этот флаг должен быть включен на уровне ПКО документа, но «тонко настроен» на уровне ПКС и ПКГС.

Резюме для практического применения

Подведем итог: наиболее надежным и современным способом является сочетание Способа 1 (настройка поиска в ТЧ) и контроля флага НеОчищать. Если же вы сталкиваетесь с неопределенностью ключевых полей (когда одну и ту же номенклатуру в ТЧ можно отличить только по номеру строки), лучше использовать Способ 2 с временным сохранением ТЧ в ПараметрыОбъекта. Это даст вам 100% уверенность в том, что лишние данные не будут потеряны или искажены в процессе обмена.

← На главную